• MySQL_索引原理与慢查询优化


    索引原理与慢查询优化

    创建/删除索引的语法

    #方法一:创建表时
          CREATE TABLE 表名 (
                    字段名1  数据类型 [完整性约束条件…],
                    字段名2  数据类型 [完整性约束条件…],
                    [UNIQUE | FULLTEXT | SPATIAL ]   INDEX | KEY
                    [索引名]  (字段名[(长度)]  [ASC |DESC])
                    );
    #方法二:CREATE在已存在的表上创建索引
            CREATE  [UNIQUE | FULLTEXT | SPATIAL ]  INDEX  索引名
                         ON 表名 (字段名[(长度)]  [ASC |DESC]) ;
    #方法三:ALTER TABLE在已存在的表上创建索引
            ALTER TABLE 表名 ADD  [UNIQUE | FULLTEXT | SPATIAL ] INDEX
                                 索引名 (字段名[(长度)]  [ASC |DESC]) ;
    #删除索引:DROP INDEX 索引名 ON 表名字;
    #方式一
    create table t1(
        id int,
        name char,
        age int,
        sex enum('male','female'),
        unique key uni_id(id),
        index ix_name(name) #index没有key
    );
    
    
    #方式二
    create index ix_age on t1(age);
    
    #方式三
    alter table t1 add index ix_sex(sex);
    View Code

    测试索引

    #准备表
    create table s1(
    id int,
    name varchar(20),
    gender char(6),
    email varchar(50)
    );
    
    #2. 创建存储过程,实现批量插入记录
    delimiter $$ #声明存储过程的结束符号为$$
    create procedure auto_insert1()
    BEGIN
        declare i int default 1;
        while(i<3000000)do
            insert into s1 values(i,'egon','male',concat('egon',i,'@oldboy'));
            set i=i+1;
        end while;
    END$$ #$$结束
    delimiter ; #重新声明分号为结束符号
    
    #3. 查看存储过程
    show create procedure auto_insert1G
    
    #4. 调用存储过程
    call auto_insert1();
    测试准备
    #在没有索引的前提下测试查询速度
    select * from s1 where id=333333333333333;
    #mysql根本就不知道到底是否存在id等于333333333的记录,只能把数据表从头到尾扫描一遍,此时有多少个磁盘块就需要进行多少IO操作,所以查询速度很慢
    #为某个字段建立索引,建立速度会很慢
    create index a on s1<id>;
    #建立索引后查询
    select * from s1 where id=3333333333;   #查询速度提升
    #一定是为搜索条件的字段创建索引
    #在表中已经有大量数据的情况下,建立索引会很慢且占用硬盘空间,建完后查询速度加快

    正确使用索引

    #添加索引时,需注意以下问题:
    
    #范围越小,条件越明确,越能提高查询速度
    #尽量选择区分度高的列作为索引
    #=和in可以乱序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式
    #索引列不能参与计算
    #1、and与or的逻辑
        条件1 and 条件2:所有条件都成立才算成立,但凡要有一个条件不成立则最终结果不成立
        条件1 or 条件2:只要有一个条件成立则最终结果就成立
    #and的工作原理
        条件:
            a = 10 and b = 'xxx' and c > 3 and d =4
        索引:
            制作联合索引(d,a,b,c)
        工作原理:
            对于连续多个and:mysql会按照联合索引,从左到右的顺序找一个区分度高的索引字段(这样便可以快速锁定很小的范围),加速查询,即按照d—>a->b->c的顺序
    #or的工作原理
        条件:
            a = 10 or b = 'xxx' or c > 3 or d =4
        索引:
            制作联合索引(d,a,b,c)
    
        工作原理:
            对于连续多个or:mysql会按照条件的顺序,从左到右依次判断,即a->b->c->d
    #最左前缀匹配原则,对于组合索引mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配(指的是范围大了,有索引速度也慢),比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整
    #使用函数
        select * from tb1 where reverse(email) = 'lary';
    #类型不一致
        如果列是字符串类型,传入条件是必须用引号引起来
        select * from tb1 where email = 999;
    #排序条件为索引,则select字段必须也是索引字段,否则无法命中
    - order by
        select name from s1 order by email desc;
        当根据索引排序时候,select查询的字段如果不是索引,则速度仍然很慢
        select email from s1 order by email desc;
        特别的:如果对主键排序,则还是速度很快:
            select * from tb1 order by nid desc;
    #组合索引最左前缀
        如果组合索引为:(name,email)
        name and email       -- 命中索引
        name                 -- 命中索引
        email                -- 未命中索引
    #count(1)或count(列)代替count(*)在mysql中没有差别了
    # create index xxxx  on tb(title(19)) #text类型,必须制定长#
    # 避免使用select *
    #count(1)或count(列) 代替 count(*)
    #创建表时尽量时 char 代替 varchar
    #表的字段顺序固定长度的字段优先
    #组合索引代替多个单列索引(经常使用多个条件查询时)
    #尽量使用短索引
    #使用连接(JOIN)来代替子查询(Sub-Queries)
    #连表时注意条件类型需一致
    #索引散列值(重复少)不适合建索引,例:性别不适合
    其他

    慢查询优化的基本步骤

    0.先运行看看是否真的很慢,注意设置SQL_NO_CACHE
    1.where条件单表查,锁定最小返回记录表。这句话的意思是把查询语句的where都应用到表中返回的记录数最小的表开始查起,单表每个字段分别查询,看哪个字段的区分度最高
    2.explain查看执行计划,是否与1预期一致(从锁定记录较少的表开始查询)
    3.order by limit 形式的sql语句让排序的表优先查
    4.了解业务方使用场景
    5.加索引时参照建索引的几大原则
    6.观察结果,不符合预期继续从0分析

    慢日志管理

    慢日志
                - 执行时间 > 10
                - 未命中索引
                - 日志文件路径
    
            配置:
                - 内存
                    show variables like '%query%';
                    show variables like '%queries%';
                    set global 变量名 = 值
                - 配置文件
                    mysqld --defaults-file='E:wupeiqimysql-5.7.16-winx64mysql-5.7.16-winx64my-default.ini'
    
                    my.conf内容:
                        slow_query_log = ON
                        slow_query_log_file = D:/....
    
                    注意:修改配置文件之后,需要重启服务
    
    MySQL日志管理
    ========================================================
    错误日志: 记录 MySQL 服务器启动、关闭及运行错误等信息
    二进制日志: 又称binlog日志,以二进制文件的方式记录数据库中除 SELECT 以外的操作
    查询日志: 记录查询的信息
    慢查询日志: 记录执行时间超过指定时间的操作
    中继日志: 备库将主库的二进制日志复制到自己的中继日志中,从而在本地进行重放
    通用日志: 审计哪个账号、在哪个时段、做了哪些事件
    事务日志或称redo日志: 记录Innodb事务相关的如事务执行时间、检查点等
    ========================================================
    一、bin-log
    1. 启用
    # vim /etc/my.cnf
    [mysqld]
    log-bin[=dir[filename]]
    # service mysqld restart
    2. 暂停
    //仅当前会话
    SET SQL_LOG_BIN=0;
    SET SQL_LOG_BIN=1;
    3. 查看
    查看全部:
    # mysqlbinlog mysql.000002
    按时间:
    # mysqlbinlog mysql.000002 --start-datetime="2012-12-05 10:02:56"
    # mysqlbinlog mysql.000002 --stop-datetime="2012-12-05 11:02:54"
    # mysqlbinlog mysql.000002 --start-datetime="2012-12-05 10:02:56" --stop-datetime="2012-12-05 11:02:54" 
    
    按字节数:
    # mysqlbinlog mysql.000002 --start-position=260
    # mysqlbinlog mysql.000002 --stop-position=260
    # mysqlbinlog mysql.000002 --start-position=260 --stop-position=930
    4. 截断bin-log(产生新的bin-log文件)
    a. 重启mysql服务器
    b. # mysql -uroot -p123 -e 'flush logs'
    5. 删除bin-log文件
    # mysql -uroot -p123 -e 'reset master' 
    
    
    二、查询日志
    启用通用查询日志
    # vim /etc/my.cnf
    [mysqld]
    log[=dir[filename]]
    # service mysqld restart
    
    三、慢查询日志
    启用慢查询日志
    # vim /etc/my.cnf
    [mysqld]
    log-slow-queries[=dir[filename]]
    long_query_time=n
    # service mysqld restart
    MySQL 5.6:
    slow-query-log=1
    slow-query-log-file=slow.log
    long_query_time=3
    查看慢查询日志
    测试:BENCHMARK(count,expr)
    SELECT BENCHMARK(50000000,2*3);

      

  • 相关阅读:
    SQL 笔记汇总
    SQL 备份数据 脚本 -添加到作业 步骤里面 可删除历史天文件
    SQL 事物
    MS-SQL2005 执行DOS命令
    笔记 hosts文件修改 网站发布二级目录 vs2008,vs2010 css验证
    自定义日期控件
    jQuery CSS3 照片墙
    CSS3 照片墙
    jquery.cookie.js
    CSS jQuery 图片全屏切换
  • 原文地址:https://www.cnblogs.com/iamluoli/p/8515509.html
Copyright © 2020-2023  润新知