zoukankan      html  css  js  c++  java
  • Mysql-索引

    MySQL索引原理

    索引的目的在于提高查询效率,如字典,查询一个单词,需要定位到首字母,然后定位第二个字母,依次来查询。如果没有索引,就需要把字典中的单词看一遍,才能找到想要的单词。

    1.b+树

    浅蓝色的块我们称之为一个磁盘块,可以看到每个磁盘块包含几个数据项(深蓝色所示)和指针(黄色所示),如磁盘块1包含数据项17和35,包含指针P1、P2、P3,P1表示小于17的磁盘块,P2表示在17和35之间的磁盘块,P3表示大于35的磁盘块。真实的数据存在于叶子节点即3、5、9、10、13、15、28、29、36、60、75、79、90、99。非叶子节点不存储真实的数据,只存储指引搜索方向的数据项,如17、35并不真实存在于数据表中。

    2.b+树查找过程

    如图所示,如果要查找数据项29,那么首先会把磁盘块1由磁盘加载到内存,此时发生一次IO,在内存中用二分查找确定29在17和35之间,锁定磁盘块1的P2指针,内存时间因为非常短(相比磁盘的IO)可以忽略不计,通过磁盘块1的P2指针的磁盘地址把磁盘块3由磁盘加载到内存,发生第二次IO,29在26和30之间,锁定磁盘块3的P2指针,通过指针加载磁盘块8到内存,发生第三次IO,同时内存中做二分查找找到29,结束查询,总计三次IO。真实的情况是,3层的b+树可以表示上百万的数据,如果上百万的数据查找只需要三次IO,性能提高将是巨大的,如果没有索引,每个数据项都要发生一次IO,那么总共需要百万次的IO,显然成本非常非常高。

    MySQL中常见的索引

    • 普通索引
    • 唯一索引
    • 主键索引
    • 组合索引
    • 全文索引
    • 索引合并
    • 覆盖索引

    1.普通索引

    功能:加速查找

    CREATE TABLE tb2(
        nid INT NOT NULL auto_increment PRIMARY KEY,
        name VARCHAR(32) NOT NULL,
        email VARCHAR(64) NOT NULL,
        extra text,
        INDEX ix_name(name)
    )ENGINE=INNODB DEFAULT charset='utf8';
    创建表时创建索引
    CREATE INDEX index_name ON table_name(colunm_name)
    仅创建索引
    DROP INDEX index_name ON table_name
    删除索引
    SHOW INDEX FROM table_name
    查看索引

    注意:创建索引时,如果字段为BLOB和text类型,必须指定length。

    2.唯一索引

    功能:加速查询、唯一约束(可以为null)

    CREATE TABLE tb2(
        nid INT NOT NULL auto_increment PRIMARY KEY,
        name VARCHAR(32) NOT NULL,
        email VARCHAR(64) NOT NULL,
        extra text,
        UNIQUE ix_name(name)
    )ENGINE=INNODB DEFAULT charset='utf8';
    创建表时创建唯一索引
    CREATE UNIQUE index_name ON table_name(colunm_name)
    创建唯一索引
    DROP UNIQUE index_name ON table_name
    删除唯一索引

    3.主键索引

    功能:加速查询、唯一约束(不可以为null)

    CREATE TABLE tb2(
        nid INT NOT NULL auto_increment PRIMARY KEY,
        name VARCHAR(32) NOT NULL,
        email VARCHAR(64) NOT NULL,
        extra text
    )ENGINE=INNODB DEFAULT charset='utf8';
    创建表时设置主键

    or

    CREATE TABLE tb2(
        nid INT NOT NULL auto_increment,
        name VARCHAR(32) NOT NULL,
        email VARCHAR(64) NOT NULL,
        extra text,
        PRIMARY KEY(nid)
    )ENGINE=INNODB DEFAULT charset='utf8';
    View Code

    注:主键时一种特殊的索引,设置主键即创建了该字段的索引。

    ALTER TABLE table_name ADD PRIMARY KEY(colunm_name)
    创建主键
    ALTER TABLE table_name DROP PRIMARY KEY
    ALTER TABLE table_name MODIFY colunm_name type,DROP PRIMARY KEY
    删除主键

    4.组合索引

    组合索引是指,将多个列组合成一个索引。

    场景:频繁地同时使用多个列进行查询。

    CREATE INDEX ix_account_email ON user(account,email)
    创建组合索引

    组合索引最左匹配:

    创建组合索引后,执行查询:

    • account和email     - 走索引
    • account       - 走索引
    • email                 - 不走索引
    select * from user where account='oliver';     #走索引
    select * from user where account='oliver' and email='asdfaskl@163.com';   #走索引
    select * from user where email='asdfaskl@163.com';   #不走索引

    5.全文索引

     对文本的内容进行分词,进行搜索

    6.索引合并

    使用多个单列索引组合搜索。如下:

    nid   name(单独索引)    email(单独索引)    pwd

    select * from tb where name='alex'
    select * from tb where email='alex3714@163.com'
            
    select * from tb where name='alex' or email='alex3714@163.com'

    7.覆盖索引

    只需要从索引中查询就能得到结果,不必再去读取数据表。

    例:

    select * from tb where nid=1    # 先从索引表中找,再去数据表中找,非覆盖索引
    select nid from tb where nid < 10   # 只需要从索引表中找,就能得到查询结果。 覆盖索引。

    执行计划

    用于显示sql执行信息,相对比较准确表达出当前SQL运行状况,用户可以参考执行信息对sql语句进行优化。

    格式: explain SQL语句

    mysql> explain select * from user where email='oliver@163.com';
    +----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+
    | id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows   | filtered | Extra       |
    +----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+
    |  1 | SIMPLE      | user  | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 261791 |    10.00 | Using where |
    +----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+
    1 row in set, 1 warning (0.00 sec)

    1.id:查询顺序标识

    2.select_type:查询类型

    • SIMPLE        简单查询
    • PRIMARY          最外层查询
    • SUBQUERY      映射为子查询
    • DERIVED          子查询
    • UNION              联合
    • UNION RESULT       使用联合的结果
    • ...

    3.table:查询的表

    4.type:查询时的访问方式

    查询时的访问方式,性能:all < index < range < index_merge < ref_or_null < ref < eq_ref < system/const

    (1)ALL 全表扫描

    遍历整个数据表,如果有limit时,找到结果后就不再往下找了。

    (2)INDEX  全索引表扫描

    (3)RANGE  对索引列进行范围查找

    mysql> explain select uid from user where uid<10200;
    +----+-------------+-------+------------+-------+---------------+---------+---------+------+-------+----------+--------------------------+
    | id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref  | rows  | filtered | Extra                    |
    +----+-------------+-------+------------+-------+---------------+---------+---------+------+-------+----------+--------------------------+
    |  1 | SIMPLE      | user  | NULL       | range | PRIMARY       | PRIMARY | 4       | NULL | 11622 |   100.00 | Using where; Using index |
    +----+-------------+-------+------------+-------+---------------+---------+---------+------+-------+----------+--------------------------+
    1 row in set, 1 warning (0.00 sec)

    (4)INDEX_MERGE 合并索引,使用多个单列索引搜索

    (5)REF   根据索引查找一个或多个值

    (6)EQ_REF  连接表时,使用primary key 或 unique类型字段

    (7)CONST   常量,表中最多有一个匹配行

    mysql> explain select uid from user where uid=10200;
    +----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
    | id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra       |
    +----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
    |  1 | SIMPLE      | user  | NULL       | const | PRIMARY       | PRIMARY | 4       | const |    1 |   100.00 | Using index |
    +----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
    1 row in set, 1 warning (0.00 sec)

    (8)SYSTEM    系统

    表仅有一行(=系统表)。这是const联接类型的一个特例。

    select * from (select nid from tb1 where nid = 1) as A;

    5.possible_keys

    可能使用的索引

    6.key

    真实使用的索引

    7.key_len

    MySQL中使用索引字节长度

    8.rows

    mysql估计为了找到所需的行而要读取的行数 ------ 只是预估值

    9.Extra   

    该列包含MySQL解决查询的详细信息

    使用索引

    要使用正确的方式命中索引。如果方式错误,即使建立了索引也无法命中。

    - like '%xx'
        select * from tb1 where name like '%cn';
    - 使用函数
        select * from tb1 where reverse(name) = 'wupeiqi';
    - or
        select * from tb1 where nid = 1 or email = 'seven@live.com';  # nid有索引,email未创建索引,则不能命中索引
        特别的:当or条件中有未建立索引的列才失效,以下会走索引
                select * from tb1 where nid = 1 or name = 'seven';   #nid和name都创建了索引,能命中索引
                select * from tb1 where nid = 1 or email = 'seven@live.com' and name = 'alex'
    - 类型不一致
        如果列是字符串类型,传入条件是必须用引号引起来,不然...
        select * from tb1 where name = 999;
    - !=
        select * from tb1 where name != 'alex'
        特别的:如果是主键,则还是会走索引
            select * from tb1 where nid != 123
    - >
        select * from tb1 where name > 'alex'
        特别的:如果是主键或索引是整数类型,则还是会走索引
            select * from tb1 where nid > 123
            select * from tb1 where num > 123
    - order by
        select email from tb1 order by name desc;
        当没有where条件时,order by主键则走索引,有where时,order by索引字段则走索引。
        特别的:如果对主键排序,则还是走索引:
            select * from tb1 order by nid desc;
     
    - 组合索引最左前缀
        如果组合索引为:(name,email)
        name and email       -- 使用索引
        name                 -- 使用索引
        email                -- 不使用索引

    注意事项

    避免使用select *
    - count(1)或count(列) 代替 count(*)
    - 创建表时尽量时 char 代替 varchar
    - 表的字段顺序固定长度的字段优先
    - 组合索引代替多个单列索引(经常使用多个条件查询时)
    - 尽量使用短索引
    - 使用连接(JOIN)来代替子查询(Sub-Queries)
    - 连表时注意条件类型需一致
    - 索引散列值(重复少)不适合建索引,例:性别不适合

    慢日志查询

    1.配置MySQL自动配置慢日志

    slow_query_log = OFF                            是否开启慢日志记录
    long_query_time = 2                              时间限制,超过此时间,则记录
    slow_query_log_file = /usr/slow.log        日志文件
    log_queries_not_using_indexes = OFF     为使用索引的搜索是否记录

    注:查看当前配置信息:
           show variables like '%query%'
         修改当前配置:
        set global 变量名 = 值

    2.查看MySQL慢日志

    mysqldumpslow -s at -a  /usr/local/var/mysql/MacBook-Pro-3-slow.log
    """
    --verbose    版本
    --debug      调试
    --help       帮助
     
    -v           版本
    -d           调试模式
    -s ORDER     排序方式
                 what to sort by (al, at, ar, c, l, r, t), 'at' is default
                  al: average lock time
                  ar: average rows sent
                  at: average query time
                   c: count
                   l: lock time
                   r: rows sent
                   t: query time
    -r           反转顺序,默认文件倒序拍。reverse the sort order (largest last instead of first)
    -t NUM       显示前N条just show the top n queries
    -a           不要将SQL中数字转换成N,字符串转换成S。don't abstract all numbers to N and strings to 'S'
    -n NUM       abstract numbers with at least n digits within names
    -g PATTERN   正则匹配;grep: only consider stmts that include this string
    -h HOSTNAME  mysql机器名或者IP;hostname of db server for *-slow.log filename (can be wildcard),
                 default is '*', i.e. match all
    -i NAME      name of server instance (if using mysql.server startup script)
    -l           总时间中不减去锁定时间;don't subtract lock time from total time
    """

       

  • 相关阅读:
    mybatis-plus 错误 java.lang.NoClassDefFoundError
    MySQL+navicat-1064 Error解决方案
    cnblogs博客园修改网站图标icon
    python+pycharm+PyQt5 图形化界面安装教程
    vuex的安装与使用
    vue-router的安装和使用
    VUE-CLI3如何更改配置
    VUE-CL3创建项目
    VUE-CLI2的初始化项目过程
    vuecli脚手架的安装与配置
  • 原文地址:https://www.cnblogs.com/pyramid1001/p/6003128.html
Copyright © 2011-2022 走看看