zoukankan      html  css  js  c++  java
  • MySQL索引

    【MySQL】MySQL索引

    目录

    • 索引的作用

    • 索引种类

    • 索引为何不可用

    • 索引原则与误区

    • 执行计划

    • 测试案例

    索引的作用

    • 提高查询效率

    • 消除数据分组/排序

    • 避免"回表"查询

    • 优化聚合查询

    • 用于多表JOIN关联查询

    • 利用唯一性约束,保证数据唯一性

    • InnoDB行锁实现

    • 增加I/O成本

    • 增加磁盘空间

    • 不适合的索引,或索引过多,都不是好事

    索引种类

    • BTREE,InnoDB & MyISAM

    • Fractal TREE,TokuDB

    • HASH HEAP NDB InnoDB AHI

    • RTREE

    • FULLTEXT

    索引讲解

    • 聚集索引

    • 主键索引

    • 唯一索引

    • 联合索引

    • 覆盖索引

    • 前缀索引

    聚集索引

    • 聚集索引是一种特殊的索引,该索引中键值的逻辑顺序决定了表数据行的物理顺序;

    • 每张表只能建一个聚集索引,除了TokuDB引擎;

    • InnoDB中,聚集索引即表,表即聚集索引;

    • MyISAM没有聚集索引的概念

    • 聚集索引优先选择列

    1. INT/BIGINT;

    1. 数据连续(单调顺序)递增/自增;

    • 不建议的聚集索引

    1. 修改频繁的列;

    1. 新增数据太过离散随机;

    • InnoDB聚集索引选择次序原则

    1. 显示声明的主键;

    1. 第一个NOT NULL的唯一索引

    1. ROWID(实例级,6bytes)

    image

    创建测试表1(显示指定主键)

    mysql> create table t(id int auto_increment,name varchar(10),primary key(id));
    Query OK, 0 rows affected (0.02 sec)
    TABLE: name test/t, id 23, flags 1, columns 5, indexes 2, appr.rows 0
      COLUMNS: id: DATA_INT DATA_BINARY_TYPE DATA_NOT_NULL len 4; name: DATA_VARMYSQL len 30; DB_ROW_ID: DATA_SYS prtype 256 len 6; DB_TRX_ID: DATA_SYS prtype 257 len 6; DB_ROLL_PTR: DATA_SYS prtype 258 len 7; 
      INDEX: name PRIMARY, id 25, fields 1/4, uniq 1, type 3
       root page 3, appr.key vals 0, leaf pages 1, size pages 1
       FIELDS:  id DB_TRX_ID DB_ROLL_PTR name
      INDEX: name idx_name, id 26, fields 1/2, uniq 2, type 0
       root page 4, appr.key vals 0, leaf pages 1, size pages 1
       FIELDS:  name id

    从上面可以看到InnoDB选择了主键id作为唯一索引,而索引idx_name为普通索引

    创建测试表2(不指定主键且指定一个非空唯一索引)

    mysql> create table t1(id int ,name varchar(10) not null,unique key idx_name(name));
    Query OK, 0 rows affected (0.01 sec)
    TABLE: name test/t1, id 25, flags 1, columns 5, indexes 1, appr.rows 0
      COLUMNS: id: DATA_INT DATA_BINARY_TYPE len 4; name: DATA_VARMYSQL DATA_NOT_NULL len 30; DB_ROW_ID: DATA_SYS prtype 256 len 6; DB_TRX_ID: DATA_SYS prtype 257 len 6; DB_ROLL_PTR: DATA_SYS prtype 258 len 7; 
      INDEX: name idx_name, id 29, fields 1/4, uniq 1, type 3
       root page 3, appr.key vals 0, leaf pages 1, size pages 1
       FIELDS:  name DB_TRX_ID DB_ROLL_PTR id

    从日志看到,聚集索引选择的是idx_name

    创建测试表3(不指定主键也无非空唯一索引)

    mysql> create table t2(id int ,name varchar(10),key idx_name(name));
    Query OK, 0 rows affected (0.02 sec)
    TABLE: name test/t2, id 26, flags 1, columns 5, indexes 2, appr.rows 0
      COLUMNS: id: DATA_INT DATA_BINARY_TYPE len 4; name: DATA_VARMYSQL len 30; DB_ROW_ID: DATA_SYS prtype 256 len 6; DB_TRX_ID: DATA_SYS prtype 257 len 6; DB_ROLL_PTR: DATA_SYS prtype 258 len 7; 
      INDEX: name GEN_CLUST_INDEX, id 30, fields 0/5, uniq 1, type 1
       root page 3, appr.key vals 0, leaf pages 1, size pages 1
       FIELDS:  DB_ROW_ID DB_TRX_ID DB_ROLL_PTR id name
      INDEX: name idx_name, id 31, fields 1/2, uniq 2, type 0
       root page 4, appr.key vals 0, leaf pages 1, size pages 1
       FIELDS:  name DB_ROW_ID

    从日志可以看出,InnoDB选择的是rowid作为聚集索引

    创建测试表4(包含以上三种索引)

    mysql> create table t3(id int auto_increment,name1 varchar(10) not null,name2 varchar(10),primary key(id),unique key idx_name1(name1),key idx_name2(name2));
    Query OK, 0 rows affected (0.02 sec)
    TABLE: name test/t3, id 27, flags 1, columns 6, indexes 3, appr.rows 0
      COLUMNS: id: DATA_INT DATA_BINARY_TYPE DATA_NOT_NULL len 4; name1: DATA_VARMYSQL DATA_NOT_NULL len 30; name2: DATA_VARMYSQL len 30; DB_ROW_ID: DATA_SYS prtype 256 len 6; DB_TRX_ID: DATA_SYS prtype 257 len 6; DB_ROLL_PTR: DATA_SYS prtype 258 len 7; 
      INDEX: name PRIMARY, id 32, fields 1/5, uniq 1, type 3
       root page 3, appr.key vals 0, leaf pages 1, size pages 1
       FIELDS:  id DB_TRX_ID DB_ROLL_PTR name1 name2
      INDEX: name idx_name1, id 33, fields 1/2, uniq 1, type 2
       root page 4, appr.key vals 0, leaf pages 1, size pages 1
       FIELDS:  name1 id
      INDEX: name idx_name2, id 34, fields 1/2, uniq 2, type 0
       root page 5, appr.key vals 0, leaf pages 1, size pages 1
       FIELDS:  name2 id

    从日志看出,InnoDB还是选择的是主键作为聚集索引

    主键索引

    • 主键由表中一个或多个字段组成,它的值用于唯一地标识表中的某一条记录;

    • 在表引用中,主键在一个表中引用来自于另一个表中的特定记录(外键foreign key应用);

    • 保证数据的完整性;

    • 加快数据的操作速度;

    • 主键值不能重复,也不能包含NULL;

    • 主键选择建议

    1. 对业务透明,无意义,免受业务变化的影响;

    1. 很少修改和删除

    1. 最好是自增;

    1. 不要具有动态属性,例如随机值;

    • 糟糕的主键选择:

    1. UUID

    1. char/varchar

    辅助索引

    • 非聚集索引,或者二级索引,俗称普通索引

    • 当通过InnoDB辅助索引来查找数据的时候,辅助索引会通过页级的指针来找到主键索引的主键,然后通过该主键索引找到相应的行数据

    • 索引定义时,不管有无显示包含主键,实际都会存储主键值;

    • 在5.6.9后,优化器已能自动识别索引末尾的主键值(Index Extensions),在这之前则需要显式加上主键列才可以被识别;

      WHERE c1 = ? AND PK = ?

      WHERE c1 = ? ORDER BY PK

    image

    唯一索引

    • 不允许具有索引值相同的行,从而禁止重复的索引或键值

    • 在唯一约束上,和主键一样(以MyISAM引擎为代表)

    • 其他不同的方面:

    1. 唯一索引允许有空值(NULL)

    1. 一个表只能有一个主键,但可以有多个唯一索引

    1. InnoDB表中主键必须是聚集索引,但聚集索引可能不是主键

    1. 唯一索引约束可临时禁用,但主键不能

    联合索引

    • 多列组成,所以也叫多列索引

    • 适合WHERE条件中的多列组合

    • 有时候,还可以用于避免回表(覆盖索引)

    • MySQL还不支持多列不同的排序规则(MySQL 8.0起支持)

    • 联合索引建议

    A.WHERE条件中,经常同时出现的列放在联合索引中

        B.把选择性(过滤性/基数)大的列放在联合索引的最左边

    • 如果第一列是范围查询,就无法用到后面的列了,可以利用ICP的特性

    • 覆盖索引就是只要利用索引数就可以得到所有的数据了

    示例

    root@localhost [xucl]>show create table testG
    *************************** 1. row ***************************
           Table: test
    Create Table: CREATE TABLE `test` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `a` varchar(10) DEFAULT NULL,
      `b` varchar(10) DEFAULT NULL,
      `c` varchar(10) DEFAULT NULL,
      PRIMARY KEY (`id`),
      KEY `idx_a_b_c` (`a`,`b`,`c`)
    ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8
    1 row in set (0.00 sec)
    
    root@localhost [xucl]>explain select * from test where a='a';
    +----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------------+
    | id | select_type | table | partitions | type | possible_keys | key       | key_len | ref   | rows | filtered | Extra       |
    +----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------------+
    |  1 | SIMPLE      | test  | NULL       | ref  | idx_a_b_c     | idx_a_b_c | 33      | const |    5 |   100.00 | Using index |
    +----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------------+
    1 row in set, 1 warning (0.00 sec)
    
    root@localhost [xucl]>explain select * from test where a='a' and b='b';
    +----+-------------+-------+------------+------+---------------+-----------+---------+-------------+------+----------+-------------+
    | id | select_type | table | partitions | type | possible_keys | key       | key_len | ref         | rows | filtered | Extra       |
    +----+-------------+-------+------------+------+---------------+-----------+---------+-------------+------+----------+-------------+
    |  1 | SIMPLE      | test  | NULL       | ref  | idx_a_b_c     | idx_a_b_c | 66      | const,const |    2 |   100.00 | Using index |
    +----+-------------+-------+------------+------+---------------+-----------+---------+-------------+------+----------+-------------+
    1 row in set, 1 warning (0.00 sec)
    
    root@localhost [xucl]>explain select * from test where a='a' and b='b' and c='c';
    +----+-------------+-------+------------+------+---------------+-----------+---------+-------------------+------+----------+-------------+
    | id | select_type | table | partitions | type | possible_keys | key       | key_len | ref               | rows | filtered | Extra       |
    +----+-------------+-------+------------+------+---------------+-----------+---------+-------------------+------+----------+-------------+
    |  1 | SIMPLE      | test  | NULL       | ref  | idx_a_b_c     | idx_a_b_c | 99      | const,const,const |    1 |   100.00 | Using index |
    +----+-------------+-------+------------+------+---------------+-----------+---------+-------------------+------+----------+-------------+
    1 row in set, 1 warning (0.00 sec)

    覆盖索引

    选择的列+where就可以覆盖索引

    执行计划里面type=index,表示full index scan,

    extra中显示using index表示覆盖索引

    示例

    root@localhost [xucl]>create table tx(
        -> id int(11) not null auto_increment comment '记录ID',
        -> shid int(11) not null comment '商店ID',
        -> gid int(11) not null comment '物品ID',
        -> type tinyint(11) not null comment '支付方式',
        -> price int(11) not null comment '物品价格',
        -> comment varchar(200) not null comment '备注',
        -> primary key(id),
        -> unique key uk_shid_gid(shid,gid),
        -> key idx_price(price),
        -> key idx_type(type)
        -> )engine=innodb auto_increment=1 default charset=utf8;
    Query OK, 0 rows affected (0.01 sec)
    
    root@localhost [xucl]>explain select id,shid,gid from tx order by shid,gid;
    +----+-------------+-------+------------+-------+---------------+-------------+---------+------+------+----------+-------------+
    | id | select_type | table | partitions | type  | possible_keys | key         | key_len | ref  | rows | filtered | Extra       |
    +----+-------------+-------+------------+-------+---------------+-------------+---------+------+------+----------+-------------+
    |  1 | SIMPLE      | tx    | NULL       | index | NULL          | uk_shid_gid | 8       | NULL |    1 |   100.00 | Using index |
    +----+-------------+-------+------------+-------+---------------+-------------+---------+------+------+----------+-------------+
    1 row in set, 1 warning (0.00 sec)

    前缀索引

    • 部分索引的原因

    A.char/varchar太长全部做索引的话,效率太差,存在浪费

    B.或者blob/text类型不能整列作为索引列,因此需要使用前缀索引

    • 部分索引选择建议

    A.统计平均值

    B.满足80%~90%覆盖度就够

    • 缺点

    无法利用前缀索引完成排序

    示例1

    root@localhost [xucl]>create table t_text(id int auto_increment primary key,url text);
    Query OK, 0 rows affected (0.02 sec)
    
    root@localhost [xucl]>select * from t_textG
    *************************** 1. row ***************************
     id: 1
    url: http://www.seomofo.com/experiments/title-and-h1-of-this-post-but-for-the-sake-of-keyword-prominence-stuffing-im-going-to-mention-it-again-using-various-synonyms-stemmed-variations-and-of-coursea-big-fat-prominent-font-size-heres-the-stumper-that-stumped-me-what-is-the-max-number-of-chars-in-a-url-that-google-is-willing-to-crawl-and-index-for-whatever-reason-i-thought-i-had-read-somewhere-that-googles-limit-on-urls-was-255-characters-but-that-turned-out-to-be-wrong-so-maybe-i-just-made-that-number-up-the-best-answer-i-could-find-was-this-quote-from-googles-webmaster-trends-analyst-john-mueller-we-can-certainly-crawl-and-index-urls-over-1000-characters-long-but-that-doesnt-mean-that-its-a-good-practice-the-setup-for-this-experiment-is-going-to-be-pretty-simple-im-going-to-edit-the-permalink-of-this-post-to-be-really-really-long-then-im-going-to-see-if-google-indexes-it-i-might-even-see-if-yahoo-and-bing-index-iteven-though-no-one-really-cares-what-those-assholes-are-doing-url-character-limits-unrelated-to-google-the-question-now-is-how-many-characters-should-i-make-the-url-of-this-post-there-are-a-couple-of-sources-ill-reference-to-help-me-make-this-decision-the-first-is-this-quote-from-the-microsoft-support-pages-microsoft-internet-explorer-has-a-maximum-uniform-resource-locator-url-length-of-2083-characters-internet-explorer-also-has-a-maximum-path-length-of-2048-characters-this-limit-applies-to-both-post-request-and-get-request-urls-the-second-source-ill-cite-is-the-http-11-protocol-which-says-the-http-protocol-does-not-place-any-a-priori-limit-on-the-length-of-a-uri-servers-must-be-able-to-handle-the-uri-of-any-resource-they-serve-and-should-be-able-to-handle-uris-of-unbounded-length-if-they-provide-get-based-forms-that-could-generate-such-uris-a-server-should-return-414-request-uri-too-long-status-if-a-uri-is-longer.html
    1 row in set (0.00 sec)
    root@localhost [xucl]>select length(url) from t_text;
    +-------------+
    | length(url) |
    +-------------+
    |        1855 |
    +-------------+
    1 row in set (0.00 sec)
    root@localhost [xucl]>create index idx_url on t_text(url);
    ERROR 1170 (42000): BLOB/TEXT column 'url' used in key specification without a key length
    root@localhost [xucl]>create index idx_url on t_text(url(255));
    Query OK, 0 rows affected (0.03 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    
    root@localhost [xucl]>show index from t_text;
    +--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
    | Table  | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
    +--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
    | t_text |          0 | PRIMARY  |            1 | id          | A         |           1 |     NULL | NULL   |      | BTREE      |         |               |
    | t_text |          1 | idx_url  |            1 | url         | A         |           1 |      255 | NULL   | YES  | BTREE      |         |               |
    +--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
    2 rows in set (0.00 sec)

    示例2

    root@localhost [xucl]>create table t_varchar(id int auto_increment primary key,url varchar(4000));
    Query OK, 0 rows affected (0.02 sec)
    
    root@localhost [xucl]>create index idx_url on t_varchar(url);
    ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes
    root@localhost [xucl]>create index idx_url on t_varchar(url(1000));
    Query OK, 0 rows affected (0.03 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    
    root@localhost [xucl]>explain select * from t_varchar where url like 'http%';
    +----+-------------+-----------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
    | id | select_type | table     | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra       |
    +----+-------------+-----------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
    |  1 | SIMPLE      | t_varchar | NULL       | range | idx_url       | idx_url | 3003    | NULL |    1 |   100.00 | Using where |
    +----+-------------+-----------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
    1 row in set, 1 warning (0.00 sec)
    • 索引最大长度767bytes

    • 启用innodb_large_prefix,增加到3072bytes,只针对DYNAMIC、COMPRESSED格式管用

    • 对于REDUNDANT、COMPACT格式,最大索引长度还是767bytes

    • MyISAM表索引最大长度是1000bytes

    • 最大默认排序长度1024bytes

    索引为何不可用

    • 通过索引扫描的记录数超过20%-30%,可能会变成全表扫描

    • 联合索引中,第一个查询条件不是最左索引列

    • 模糊查询条件最左以通配符%开始

    • 多表关联时,排序字段不属于驱动表,无法利用索引完成排序

    • JOIN查询时,关联数据类型(字符集)不一致也会导致索引不可用

    索引原则与误区

    原则1:单表索引数不要超过5个

    root@localhost [xucl]>show create table wcmchnldocG
    *************************** 1. row ***************************
           Table: wcmchnldoc
    Create Table: CREATE TABLE `wcmchnldoc` (
      `CHNLID` int(11) NOT NULL,
      `DOCID` int(11) NOT NULL,
      `DOCORDER` int(11) NOT NULL DEFAULT '0',
      `DOCSTATUS` int(11) NOT NULL DEFAULT '0',
      `CRUSER` varchar(100) NOT NULL DEFAULT 'admin',
      ....
      PRIMARY KEY (`RECID`),
      KEY `IX_WCMCHNLDOC_CHNL_DOC` (`CHNLID`,`DOCID`) USING BTREE,
      KEY `IX_WCMCHNLDOC_CHNL_ORDER` (`CHNLID`,`DOCORDER`) USING BTREE,
      KEY `IX_WCMCHNLDOC_CRDEPT` (`CRDEPT`) USING BTREE,
      KEY `IX_WCMCHNLDOC_CRTIMEUDSCSDF` (`CRTIME`,`CRUSER`,`DOCSTATUS`,`CHNLID`,`SITEID`,`DOCFORM`) USING BTREE,
      KEY `IX_WCMCHNLDOC_CRTIMEUDSCSDO` (`CRTIME`,`CRUSER`,`DOCSTATUS`,`CHNLID`,`SITEID`,`DOCOUTUPID`) USING BTREE,
      KEY `IX_WCMCHNLDOC_CRTIMEUDSCSM` (`CRTIME`,`CRUSER`,`DOCSTATUS`,`CHNLID`,`SITEID`,`MODAL`) USING BTREE,
      KEY `IX_WCMCHNLDOC_CRUSER` (`CRUSER`) USING BTREE,
      KEY `IX_WCMCHNLDOC_DOCFIRSTPUBTIME` (`DOCFIRSTPUBTIME`) USING BTREE,
      KEY `IX_WCMCHNLDOC_DOCTYPE` (`DOCTYPE`) USING BTREE,
      KEY `IX_WCMCHNLDOC_DOCID_MODAL` (`DOCID`,`MODAL`) USING BTREE,
      KEY `IX_WCMChnlDoc_OriginDocId_SiteId_CrTime` (`OriginDocId`,`SITEID`,`CRTIME`) USING BTREE,
      KEY `IX_WCMChnlDoc_SiteId_OriginDocId` (`SITEID`,`OriginDocId`) USING BTREE,
      KEY `IX_WCMChnlDoc_CrUserStatus` (`DOCKIND`,`CRUSER`,`DOCSTATUS`),
      KEY `IX_WCMChnlDoc_SiteIdStatus` (`DOCKIND`,`SITEID`,`DOCSTATUS`),
      KEY `IX_WCMChnlDoc_PubTimeChnlStatus` (`DOCKIND`,`DOCPUBTIME`,`CHNLID`,`DOCSTATUS`),
      KEY `IX_WCMChnlDoc_CrUserSiteStatus` (`DOCKIND`,`CRUSER`,`SITEID`,`DOCSTATUS`),
      KEY `idx_DocId_SrcMetaDataId` (`DOCID`,`SrcMetaDataId`),
      KEY `idx_SrcMetaDataId` (`SrcMetaDataId`),
      KEY `idx_doc_chl_sta_pub` (`DOCKIND`,`CHNLID`,`DOCSTATUS`,`ISTIMINGPUBLISH`,`OPERTIME`),
      KEY `idx_chnlid_docstatus_dockind_docpubtime` (`CHNLID`,`DOCSTATUS`,`DOCKIND`,`DOCPUBTIME`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8
    
    root@localhost [xucl]>show create table wcmchnldocG
    *************************** 1. row ***************************
           Table: wcmchnldoc
    Create Table: CREATE TABLE `wcmchnldoc` (
      `CHNLID` int(11) NOT NULL,
      `DOCID` int(11) NOT NULL,
      `DOCORDER` int(11) NOT NULL DEFAULT '0',
      `DOCSTATUS` int(11) NOT NULL DEFAULT '0',
      `CRUSER` varchar(100) NOT NULL DEFAULT 'admin',
      `CRTIME` datetime DEFAULT NULL,
     ....
      PRIMARY KEY (`id`),
      UNIQUE KEY `uk_recid` (`RECID`),
      KEY `idx_docpuburl_doctype` (`DOCPUBURL`,`DOCTYPE`)
    ) ENGINE=InnoDB AUTO_INCREMENT=7824427 DEFAULT CHARSET=utf8
    1 row in set (0.00 sec)

    大小对比

    MariaDB [information_schema]> select (sum(DATA_LENGTH)+sum(INDEX_LENGTH))/1024/1024/1024 from tables where table_name = 'wcmchnldoc';
    +-----------------------------------------------------+
    | (sum(DATA_LENGTH)+sum(INDEX_LENGTH))/1024/1024/1024 |
    +-----------------------------------------------------+
    |                                      7.618774414063 |
    +-----------------------------------------------------+
    1 row in set (0.02 sec)
    
    root@localhost [xucl]>select (sum(DATA_LENGTH)+sum(INDEX_LENGTH))/1024/1024/1024 from information_schema.tables where table_name = 'wcmchnldoc';
    +-----------------------------------------------------+
    | (sum(DATA_LENGTH)+sum(INDEX_LENGTH))/1024/1024/1024 |
    +-----------------------------------------------------+
    |                                      1.877914428711 |
    +-----------------------------------------------------+
    1 row in set (0.00 sec)

    数据导入对比

    root@localhost [xucl]>load data infile '/tmp/wcmchnldoc' into table wcmchnldoc;                                                                                                                                   
    Query OK, 1000000 rows affected (2 min 20.64 sec)
    Records: 1000000  Deleted: 0  Skipped: 0  Warnings: 0
    
    root@localhost [xucl]>load data infile '/tmp/wcmchnldoc' into table wcmchnldoc;                                                                                                                                   
    Query OK, 1000000 rows affected (23.89 sec)
    Records: 1000000  Deleted: 0  Skipped: 0  Warnings: 0

    140S  VS 24S

    原则2:单个索引列不要超过5个

    原则3:多列索引满足最左匹配原则

    原则4:区分度高的列放在索引的左边

    root@localhost [xucl]>show create table tttG
    *************************** 1. row ***************************
           Table: ttt
    Create Table: CREATE TABLE `ttt` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `status` int(11) DEFAULT NULL,
      `chnnel_id` int(11) DEFAULT NULL,
      `docid` int(11) DEFAULT NULL,
      `remark` varchar(100) DEFAULT '',
      PRIMARY KEY (`id`),
      UNIQUE KEY `uk_docid` (`docid`),
      KEY `idx_status_chnnel_docid` (`status`,`chnnel_id`,`docid`)
    ) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8
    1 row in set (0.00 sec)
    
    root@localhost [xucl]>select * from ttt;
    +-----+--------+-----------+-------+--------+
    | id  | status | chnnel_id | docid | remark |
    +-----+--------+-----------+-------+--------+
    |  19 |      1 |         1 |   120 |        |
    |  20 |      1 |         1 |   121 |        |
    |  21 |      1 |         2 |   122 |        |
    |  22 |      1 |         2 |   123 |        |
    |  23 |      0 |         3 |   124 |        |
    |  24 |      0 |         3 |   125 |        |
    |  25 |      0 |         4 |   126 |        |
    |  26 |      0 |         5 |   127 |        |
          |
    ...
    |  99 |      1 |         1 |   201 |        |
    | 100 |      1 |         1 |   202 |        |
    | 101 |      1 |         2 |   203 |        |
    | 102 |      1 |         2 |   204 |        |
    | 103 |      0 |         3 |   205 |        |
    | 104 |      0 |         3 |   206 |        |
    | 105 |      0 |         4 |   207 |        |
    | 106 |      0 |         5 |   208 |        |
    | 107 |      1 |         1 |   209 |        |
    | 108 |      1 |         1 |   210 |        |
    | 109 |      1 |         2 |   211 |        |
    | 110 |      1 |         2 |   212 |        |
    | 111 |      0 |         3 |   213 |        |
    | 112 |      0 |         3 |   214 |        |
    | 113 |      0 |         4 |   215 |        |
    | 114 |      0 |         5 |   216 |        |
    | 115 |      1 |         1 |   217 |        |
    | 116 |      1 |         1 |   218 |        |
    | 117 |      1 |         2 |   219 |        |
    | 118 |      1 |         2 |   220 |        |
    | 119 |      0 |         3 |   221 |        |
    | 120 |      0 |         3 |   222 |        |
    | 121 |      0 |         4 |   223 |        |
    | 122 |      0 |         5 |   224 |        |
    +-----+--------+-----------+-------+--------+
    103 rows in set (0.00 sec)
    root@localhost [xucl]>select count(distinct(status))/count(*),count(distinct(chnnel_id))/count(*),count(distinct(docid))/count(*) from ttt;
    +----------------------------------+-------------------------------------+---------------------------------+
    | count(distinct(status))/count(*) | count(distinct(chnnel_id))/count(*) | count(distinct(docid))/count(*) |
    +----------------------------------+-------------------------------------+---------------------------------+
    |                           0.0194 |                              0.0485 |                          1.0000 |
    +----------------------------------+-------------------------------------+---------------------------------+
    1 row in set (0.00 sec)
    root@localhost [xucl]>explain select * from ttt where status=1 and chnnel_id=2 and docid in (120,121,122,130);
    +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
    | id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
    +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
    |  1 | SIMPLE      | ttt   | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    8 |    12.50 | Using where |
    +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
    1 row in set, 1 warning (0.00 sec)
    root@localhost [xucl]>create index idx_status_chnnel_docid on ttt(status,chnnel_id,docid);
    Query OK, 0 rows affected (0.02 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    root@localhost [xucl]>show index from ttt;
    +-------+------------+-------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
    | Table | Non_unique | Key_name                | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
    +-------+------------+-------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
    | ttt   |          0 | PRIMARY                 |            1 | id          | A         |           8 |     NULL | NULL   |      | BTREE      |         |               |
    | ttt   |          0 | uk_docid                |            1 | docid       | A         |           8 |     NULL | NULL   | YES  | BTREE      |         |               |
    | ttt   |          1 | idx_status_chnnel_docid |            1 | status      | A         |           2 |     NULL | NULL   | YES  | BTREE      |         |               |
    | ttt   |          1 | idx_status_chnnel_docid |            2 | chnnel_id   | A         |           5 |     NULL | NULL   | YES  | BTREE      |         |               |
    | ttt   |          1 | idx_status_chnnel_docid |            3 | docid       | A         |           8 |     NULL | NULL   | YES  | BTREE      |         |               |
    +-------+------------+-------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
    5 rows in set (0.00 sec)
    root@localhost [xucl]>explain select * from ttt where status=1 and chnnel_id=2 and docid in (120,121,122,130);
    +----+-------------+-------+------------+-------+----------------------------------+-------------------------+---------+------+------+----------+-----------------------+
    | id | select_type | table | partitions | type  | possible_keys                    | key                     | key_len | ref  | rows | filtered | Extra                 |
    +----+-------------+-------+------------+-------+----------------------------------+-------------------------+---------+------+------+----------+-----------------------+
    |  1 | SIMPLE      | ttt   | NULL       | range | uk_docid,idx_status_chnnel_docid | idx_status_chnnel_docid | 15      | NULL |    4 |   100.00 | Using index condition |
    +----+-------------+-------+------------+-------+----------------------------------+-------------------------+---------+------+------+----------+-----------------------+
    1 row in set, 1 warning (0.00 sec)
    #假如有如下SQL如何能够利用到该索引呢?
    root@localhost [xucl]>explain select * from ttt where chnnel_id=2 and docid in (120,121,122,130);
    +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
    | id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
    +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
    |  1 | SIMPLE      | ttt   | NULL       | ALL  | NULL          | NULL | NULL    | NULL |  103 |     4.00 | Using where |
    +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
    1 row in set, 1 warning (0.00 sec)
    root@localhost [xucl]>explain select * from ttt where status in (0,1) and chnnel_id=2 and docid in (120,121,122,130);
    +----+-------------+-------+------------+-------+-------------------------+-------------------------+---------+------+------+----------+-----------------------+
    | id | select_type | table | partitions | type  | possible_keys           | key                     | key_len | ref  | rows | filtered | Extra                 |
    +----+-------------+-------+------------+-------+-------------------------+-------------------------+---------+------+------+----------+-----------------------+
    |  1 | SIMPLE      | ttt   | NULL       | range | idx_status_chnnel_docid | idx_status_chnnel_docid | 15      | NULL |    8 |   100.00 | Using index condition |
    +----+-------------+-------+------------+-------+-------------------------+-------------------------+---------+------+------+----------+-----------------------+
    1 row in set, 1 warning (0.00 sec)

    原则5:default ''与default null

    误区1:谓词'!='无法用到索引

    root@localhost [xucl]>show create table testG
    *************************** 1. row ***************************
           Table: test
    Create Table: CREATE TABLE `test` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `a` varchar(10) DEFAULT NULL,
      `b` varchar(10) DEFAULT NULL,
      `c` varchar(10) DEFAULT NULL,
      PRIMARY KEY (`id`),
      KEY `idx_a_b_c` (`a`,`b`,`c`)
    ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8
    1 row in set (0.00 sec)
    
    root@localhost [xucl]>select * from test where a is not null;
    +----+------+------+------+
    | id | a    | b    | c    |
    +----+------+------+------+
    |  2 | a    | a    |      |
    |  3 | a    | a    | d    |
    |  1 | a    | b    | c    |
    |  4 | a    | b    | d    |
    |  5 | a    | e    | d    |
    |  6 | b    | e    | d    |
    |  7 | e    | e    | d    |
    |  8 | g    | e    | d    |
    |  9 | h    | e    | d    |
    | 10 | h    | i    | d    |
    +----+------+------+------+
    10 rows in set (0.00 sec)
    
    root@localhost [xucl]>desc select * from test where a !='a';
    +----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+--------------------------+
    | id | select_type | table | partitions | type  | possible_keys | key       | key_len | ref  | rows | filtered | Extra                    |
    +----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+--------------------------+
    |  1 | SIMPLE      | test  | NULL       | range | idx_a_b_c     | idx_a_b_c | 33      | NULL |    6 |   100.00 | Using where; Using index |
    +----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+--------------------------+
    1 row in set, 1 warning (0.00 sec)

    误区2:谓词'is not null'无法用到索引

    root@localhost [xucl]>desc select * from test where a is not null;
    +----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+--------------------------+
    | id | select_type | table | partitions | type  | possible_keys | key       | key_len | ref  | rows | filtered | Extra                    |
    +----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+--------------------------+
    |  1 | SIMPLE      | test  | NULL       | index | idx_a_b_c     | idx_a_b_c | 99      | NULL |   10 |   100.00 | Using where; Using index |
    +----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+--------------------------+
    1 row in set, 1 warning (0.00 sec)

    执行计划

    示例

    root@localhost [xucl]>explain SELECT wcmchnldoc0_.recid AS recid1_1_, wcmchnldoc0_.chnlid AS chnlid2_1_, wcmchnldoc0_.docfirstpubtime AS docfirst3_1_, wcmchnldoc0_.docid AS docid4_1_,  wcmchnldoc0_.docpubtime AS docpubti5_1_, wcmchnldoc0_.docpuburl AS docpubur6_1_, wcmchnldoc0_.doctype AS doctype7_1_, wcmchnldoc0_.modal AS modal8_1_  FROM wcmchnldoc wcmchnldoc0_  WHHERE wcmchnldoc0_.docpuburl = 'http://photo.zjol.com.cn/yuanchuang/201807/t20180721_7834159.shtml'  AND wcmchnldoc0_.doctype <> 4;
    +----+-------------+--------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
    | id | select_type | table        | partitions | type | possible_keys | key  | key_len | ref  | rows    | filtered | Extra       |
    +----+-------------+--------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
    |  1 | SIMPLE      | wcmchnldoc0_ | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 7531425 |     9.00 | Using where |
    +----+-------------+--------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
    1 row in set, 1 warning (0.00 sec)

    注意事项

    • type:all全表扫描,最糟糕的情况;index全索引扫描,大部分情况下一样糟糕

    • key_len计算规则

      • 正常地,等于索引列字节长度

      • 字符串类型需要同时考虑字符集因素

      • 若允许NULL再+1

      • 变长类型(VARCHAR),再+2

      • key_len只计算利用索引完成数据过滤时的索引长度

      • 不包括用于GROUP BY/ORDER BY的索引的长度

    • extra说明:

      • Using filesort

        • 没有办法利用现有索引进行排序,需要额外排序

        • 建议:根据排序需要,创建相应合适的索引

      • Using index

        • 利用覆盖索引,无需回表即可取得结果数据

      • Using temporary

        • 需要用临时表存储结果集,通常是因为group by的列上没有索引也有可能是因为同时有group by和order by,但group by和order by的列又不一样

    优化案例

    案例1(hash)

    root@localhost [xucl]>show create table wcmchnldocG
    *************************** 1. row ***************************
           Table: wcmchnldoc
    Create Table: CREATE TABLE `wcmchnldoc` (
      `CHNLID` int(11) NOT NULL,
      `DOCID` int(11) NOT NULL,
      `DOCORDER` int(11) NOT NULL DEFAULT '0',
      `DOCSTATUS` int(11) NOT NULL DEFAULT '0',
      `CRUSER` varchar(100) NOT NULL DEFAULT 'admin',
      `CRTIME` datetime DEFAULT NULL,
      `DOCPUBTIME` datetime DEFAULT NULL,
      `DOCPUBURL` varchar(300) DEFAULT NULL,
      `RECID` int(11) NOT NULL,
      `DOCORDERPRI` int(11) NOT NULL DEFAULT '0',
      `INVALIDTIME` datetime DEFAULT NULL,
      `OPERUSER` varchar(50) DEFAULT NULL,
      `OPERTIME` datetime DEFAULT NULL,
      `MODAL` int(11) DEFAULT '1',
      `DOCRELTIME` datetime DEFAULT NULL,
      `DOCCHANNEL` int(11) DEFAULT NULL,
      `DOCFLAG` int(11) DEFAULT NULL,
      `DOCKIND` int(11) DEFAULT '0',
      `SITEID` int(11) NOT NULL DEFAULT '0',
      `SRCSITEID` int(11) NOT NULL DEFAULT '0',
      `DOCFIRSTPUBTIME` datetime DEFAULT NULL,
      `NODEID` int(11) DEFAULT '0',
      `CRDEPT` varchar(200) DEFAULT NULL,
      `DOCOUTUPID` int(11) DEFAULT '0',
      `DOCFORM` int(11) DEFAULT '0',
      `DOCLEVEL` int(11) DEFAULT NULL,
      `attachpic` smallint(6) DEFAULT NULL,
      `POSCHNLID` int(11) DEFAULT '0',
      `ISPUSHTOPCHNL` int(2) DEFAULT '0',
      `HIDDEN` int(2) DEFAULT '0',
      `DOCTYPE` int(2) DEFAULT '0',
      `ISTIMINGPUBLISH` int(2) DEFAULT '0',
      `GDORDER` int(2) DEFAULT NULL,
      `setTopInfo` varchar(100) DEFAULT NULL,
      `OriginDocId` int(9) DEFAULT NULL,
      `ATTACHVIDEO` int(2) DEFAULT '0',
      `ATTACHAUDIO` int(2) DEFAULT '0',
      `SrcMetaDataId` int(11) DEFAULT NULL,
      `pubUser` varchar(50) DEFAULT NULL,
      `mrsFlag` int(2) DEFAULT NULL,
      `timingPubUser` varchar(50) DEFAULT NULL,
      `isTransmit` int(2) DEFAULT NULL,
      `TIMINGPUBUSERDEPT` varchar(200) DEFAULT NULL,
      `PUBUSERDEPT` varchar(200) DEFAULT NULL,
      `DocOldStatus` int(11) DEFAULT '0',
      `isZhengShen` int(2) DEFAULT '0',
      `ClientExamine` int(2) DEFAULT '0',
      `srcChannelId` int(11) DEFAULT NULL,
      PRIMARY KEY (`RECID`),
      KEY `IX_WCMCHNLDOC_CHNL_DOC` (`CHNLID`,`DOCID`) USING BTREE,
      KEY `IX_WCMCHNLDOC_CHNL_ORDER` (`CHNLID`,`DOCORDER`) USING BTREE,
      KEY `IX_WCMCHNLDOC_CRDEPT` (`CRDEPT`) USING BTREE,
      KEY `IX_WCMCHNLDOC_CRTIMEUDSCSDF` (`CRTIME`,`CRUSER`,`DOCSTATUS`,`CHNLID`,`SITEID`,`DOCFORM`) USING BTREE,
      KEY `IX_WCMCHNLDOC_CRTIMEUDSCSDO` (`CRTIME`,`CRUSER`,`DOCSTATUS`,`CHNLID`,`SITEID`,`DOCOUTUPID`) USING BTREE,
      KEY `IX_WCMCHNLDOC_CRTIMEUDSCSM` (`CRTIME`,`CRUSER`,`DOCSTATUS`,`CHNLID`,`SITEID`,`MODAL`) USING BTREE,
      KEY `IX_WCMCHNLDOC_CRUSER` (`CRUSER`) USING BTREE,
      KEY `IX_WCMCHNLDOC_DOCFIRSTPUBTIME` (`DOCFIRSTPUBTIME`) USING BTREE,
      KEY `IX_WCMCHNLDOC_DOCTYPE` (`DOCTYPE`) USING BTREE,
      KEY `IX_WCMCHNLDOC_DOCID_MODAL` (`DOCID`,`MODAL`) USING BTREE,
      KEY `IX_WCMChnlDoc_OriginDocId_SiteId_CrTime` (`OriginDocId`,`SITEID`,`CRTIME`) USING BTREE,
      KEY `IX_WCMChnlDoc_SiteId_OriginDocId` (`SITEID`,`OriginDocId`) USING BTREE,
      KEY `IX_WCMChnlDoc_CrUserStatus` (`DOCKIND`,`CRUSER`,`DOCSTATUS`),
      KEY `IX_WCMChnlDoc_SiteIdStatus` (`DOCKIND`,`SITEID`,`DOCSTATUS`),
      KEY `IX_WCMChnlDoc_PubTimeChnlStatus` (`DOCKIND`,`DOCPUBTIME`,`CHNLID`,`DOCSTATUS`),
      KEY `IX_WCMChnlDoc_CrUserSiteStatus` (`DOCKIND`,`CRUSER`,`SITEID`,`DOCSTATUS`),
      KEY `idx_DocId_SrcMetaDataId` (`DOCID`,`SrcMetaDataId`),
      KEY `idx_SrcMetaDataId` (`SrcMetaDataId`),
      KEY `idx_doc_chl_sta_pub` (`DOCKIND`,`CHNLID`,`DOCSTATUS`,`ISTIMINGPUBLISH`,`OPERTIME`),
      KEY `idx_chnlid_docstatus_dockind_docpubtime` (`CHNLID`,`DOCSTATUS`,`DOCKIND`,`DOCPUBTIME`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8
    root@localhost [xucl]>SELECT
    -> wcmchnldoc0_.recid AS recid1_1_,
    -> wcmchnldoc0_.chnlid AS chnlid2_1_,
    -> wcmchnldoc0_.docfirstpubtime AS docfirst3_1_,
    -> wcmchnldoc0_.docid AS docid4_1_,
    -> wcmchnldoc0_.docpubtime AS docpubti5_1_,
    -> wcmchnldoc0_.docpuburl AS docpubur6_1_,
    -> wcmchnldoc0_.doctype AS doctype7_1_,
    -> wcmchnldoc0_.modal AS modal8_1_ 
    -> FROM
    -> wcmchnldoc wcmchnldoc0_ 
    -> WHERE
    -> wcmchnldoc0_.docpuburl = 'http://photo.zjol.com.cn/yuanchuang/201807/t20180721_7834159.shtml' 
    -> AND wcmchnldoc0_.doctype <> 4;
    +-----------+------------+---------------------+-----------+---------------------+--------------------------------------------------------------------+-------------+-----------+
    | recid1_1_ | chnlid2_1_ | docfirst3_1_        | docid4_1_ | docpubti5_1_        | docpubur6_1_                                                       | doctype7_1_ | modal8_1_ |
    +-----------+------------+---------------------+-----------+---------------------+--------------------------------------------------------------------+-------------+-----------+
    |   8114327 |       4297 | 2018-07-21 20:49:13 |   7834159 | 2018-07-21 20:49:13 | http://photo.zjol.com.cn/yuanchuang/201807/t20180721_7834159.shtml |           2 |         1 |
    +-----------+------------+---------------------+-----------+---------------------+--------------------------------------------------------------------+-------------+-----------+
    1 row in set (50.47 sec)
    root@localhost [xucl]>explain SELECT wcmchnldoc0_.recid AS recid1_1_, wcmchnldoc0_.chnlid AS chnlid2_1_, wcmchnldoc0_.docfirstpubtime AS docfirst3_1_, wcmchnldoc0_.docid AS docid4_1_,  wcmchnldoc0_.docpubtime AS docpubti5_1_, wcmchnldoc0_.docpuburl AS docpubur6_1_, wcmchnldoc0_.doctype AS doctype7_1_, wcmchnldoc0_.modal AS modal8_1_  FROM wcmchnldoc wcmchnldoc0_  WHHERE wcmchnldoc0_.docpuburl = 'http://photo.zjol.com.cn/yuanchuang/201807/t20180721_7834159.shtml'  AND wcmchnldoc0_.doctype <> 4;
    +----+-------------+--------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
    | id | select_type | table        | partitions | type | possible_keys | key  | key_len | ref  | rows    | filtered | Extra       |
    +----+-------------+--------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
    |  1 | SIMPLE      | wcmchnldoc0_ | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 7531425 |     9.00 | Using where |
    +----+-------------+--------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
    1 row in set, 1 warning (0.00 sec)
    优化1:
    root@localhost [xucl]>show create table wcmchnldocG
    *************************** 1. row ***************************
    Table: wcmchnldoc
    Create Table: CREATE TABLE `wcmchnldoc` (
      `CHNLID` int(11) NOT NULL,
      `DOCID` int(11) NOT NULL,
      `DOCORDER` int(11) NOT NULL DEFAULT '0',
      `DOCSTATUS` int(11) NOT NULL DEFAULT '0',
      `CRUSER` varchar(100) NOT NULL DEFAULT 'admin',
      `CRTIME` datetime DEFAULT NULL,
      `DOCPUBTIME` datetime DEFAULT NULL,
      `DOCPUBURL` varchar(300) DEFAULT NULL,
      `RECID` int(11) NOT NULL,
      `DOCTYPE` int(2) DEFAULT '0',
      `id` int(11) NOT NULL AUTO_INCREMENT,
      PRIMARY KEY (`id`),
      UNIQUE KEY `uk_recid` (`RECID`),
      KEY `idx_docpuburl_doctype` (`DOCPUBURL`,`DOCTYPE`)
    ) ENGINE=InnoDB AUTO_INCREMENT=7824427 DEFAULT CHARSET=utf8
    1 row in set (0.00 sec)
    root@localhost [xucl]>SELECT wcmchnldoc0_.recid AS recid1_1_, wcmchnldoc0_.chnlid AS chnlid2_1_, wcmchnldoc0_.docfirstpubtime AS docfirst3_1_, wcmchnldoc0_.docid AS docid4_1_, wcmchnldoc0_.docpubtime AS docpubti5_1_, wcmchnldoc0_.docpuburl AS docpubur6_1_, wcmchnldoc0_.doctype AS doctype7_1_, wcmchnldoc0_.modal AS modal8_1_  FROM wcmchnldoc wcmchnldoc0_  WHERE wcmchnldoc0_.docpuburl = 'http://photo.zjol.com.cn/yuanchuang/201807/t20180721_7834159.shtml'  AND wcmchnldoc0_.doctype <> 4;
    +-----------+------------+---------------------+-----------+---------------------+--------------------------------------------------------------------+-------------+-----------+
    | recid1_1_ | chnlid2_1_ | docfirst3_1_        | docid4_1_ | docpubti5_1_        | docpubur6_1_                                                       | doctype7_1_ | modal8_1_ |
    +-----------+------------+---------------------+-----------+---------------------+--------------------------------------------------------------------+-------------+-----------+
    |   8114327 |       4297 | 2018-07-21 20:49:13 |   7834159 | 2018-07-21 20:49:13 | http://photo.zjol.com.cn/yuanchuang/201807/t20180721_7834159.shtml |           2 |         1 |
    +-----------+------------+---------------------+-----------+---------------------+--------------------------------------------------------------------+-------------+-----------+
    1 row in set (0.00 sec)
    优化2:
    增加列
    docpuburl_crc32
    增加索引
    idx_crc32
    root@localhost [xucl]>show create table wcmchnldocG
    *************************** 1. row ***************************
    Table: wcmchnldoc
    Create Table: CREATE TABLE `wcmchnldoc` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `DOCPUBURL` varchar(300) DEFAULT NULL,
      `RECID` int(11) NOT NULL,
      `DOCORDERPRI` int(11) NOT NULL DEFAULT '0',
      `INVALIDTIME` datetime DEFAULT NULL,
      `OPERUSER` varchar(50) DEFAULT NULL,
      `DOCTYPE` int(2) DEFAULT '0',
      `docpuburl_crc32` bigint(20) DEFAULT NULL,
      PRIMARY KEY (`id`),
      UNIQUE KEY `uk_recid` (`RECID`),
      KEY `idx_docpuburl_doctype` (`DOCPUBURL`,`DOCTYPE`),
      KEY `idx_crc32` (`docpuburl_crc32`)
    ) ENGINE=InnoDB AUTO_INCREMENT=7824427 DEFAULT CHARSET=utf8
    root@localhost [xucl]>desc SELECT wcmchnldoc0_.recid AS recid1_1_, wcmchnldoc0_.chnlid AS chnlid2_1_, wcmchnldoc0_.docfirstpubtime AS docfirst3_1_, wcmchnldoc0_.docid AS docid4_1_, wcmmchnldoc0_.docpubtime AS docpubti5_1_, wcmchnldoc0_.docpuburl AS docpubur6_1_, wcmchnldoc0_.doctype AS doctype7_1_, wcmchnldoc0_.modal AS modal8_1_  FROM wcmchnldoc wcmchnldoc0_  WHEREE   wcmchnldoc0_.docpuburl_crc32 = 466484933 AND wcmchnldoc0_.doctype <> 4;
    +----+-------------+--------------+------------+------+---------------+-----------+---------+-------+------+----------+-------------+
    | id | select_type | table        | partitions | type | possible_keys | key       | key_len | ref   | rows | filtered | Extra       |
    +----+-------------+--------------+------------+------+---------------+-----------+---------+-------+------+----------+-------------+
    |  1 | SIMPLE      | wcmchnldoc0_ | NULL       | ref  | idx_crc32     | idx_crc32 | 9       | const |    2 |    90.00 | Using where |
    +----+-------------+--------------+------------+------+---------------+-----------+---------+-------+------+----------+-------------+
    1 row in set, 1 warning (0.00 sec)
    问题点:
    hash值重复
    解决方法
    root@localhost [xucl]>explain SELECT wcmchnldoc0_.recid AS recid1_1_, wcmchnldoc0_.chnlid AS chnlid2_1_, wcmchnldoc0_.docfirstpubtime AS docfirst3_1_, wcmchnldoc0_.docid AS docid4_1_,  wcmchnldoc0_.docpubtime AS docpubti5_1_, wcmchnldoc0_.docpuburl AS docpubur6_1_, wcmchnldoc0_.doctype AS doctype7_1_, wcmchnldoc0_.modal AS modal8_1_  FROM wcmchnldoc wcmchnldoc0_  WHHERE   wcmchnldoc0_.docpuburl_crc32 = 466484933 AND wcmchnldoc0_.doctype <> 4 AND wcmchnldoc0_.docpuburl = 'http://photo.zjol.com.cn/yuanchuang/201807/t20180721_7834159.shtml';
    +----+-------------+--------------+------------+------+---------------------------------+-----------+---------+-------+------+----------+-------------+
    | id | select_type | table        | partitions | type | possible_keys                   | key       | key_len | ref   | rows | filtered | Extra       |
    +----+-------------+--------------+------------+------+---------------------------------+-----------+---------+-------+------+----------+-------------+
    |  1 | SIMPLE      | wcmchnldoc0_ | NULL       | ref  | idx_docpuburl_doctype,idx_crc32 | idx_crc32 | 9       | const |    2 |     2.50 | Using where |
    +----+-------------+--------------+------------+------+---------------------------------+-----------+---------+-------+------+----------+-------------+
    1 row in set, 1 warning (0.00 sec)

    案例2(索引字段顺序)

    MariaDB [trswcmtest]> explain select SITEID,RECID,CHNLID,DOCID,DOCORDER,DOCSTATUS,CRUSER,CRTIME,DOCPUBTIME,DOCPUBURL,DOCORDERPRI,INVALIDTIME,OPERUSER,OPERTIME,MODAL,DOCRELTIME,DOCCHANNEL,DOCFLAG,DOCKIND,'zjrb_mlf',now(),now(),'xuguozheng','xuguozheng' from wcmchnldoc where DOCPUBTIME >= date_add(STR_TO_DATE('2018-08-14', '%Y-%m-%d'), interval -14 day) and DOCPUBTIME <= STR_TO_DATE('2018-08-14', '%Y-%m-%d') and SITEID=198 and DOCSTATUS=10;
    +------+-------------+------------+------+----------------------------------+----------------------------------+---------+-------+---------+-------------+
    | id   | select_type | table      | type | possible_keys                    | key                              | key_len | ref   | rows    | Extra       |
    +------+-------------+------------+------+----------------------------------+----------------------------------+---------+-------+---------+-------------+
    |    1 | SIMPLE      | wcmchnldoc | ref  | IX_WCMChnlDoc_SiteId_OriginDocId | IX_WCMChnlDoc_SiteId_OriginDocId | 4       | const | 2362574 | Using where |
    +------+-------------+------------+------+----------------------------------+----------------------------------+---------+-------+---------+-------------+
    1 row in set (0.00 sec)
    
    ....
    |    198 | 8255364 |  12425 | 7966282 |    27419 |        10 | mll             | 2018-08-08 06:59:38 | 2018-08-08 07:02:26 | NULL                                                                     |           0 | NULL        | mll             | 2018-08-08 07:02:26 |     1 | 2018-08-08 06:59:38 |      12425 |    NULL |       6 | zjrb_mlf | 2018-08-14 17:52:12 | 2018-08-14 17:52:12 | xuguozheng | xuguozheng |
    Ctrl-C -- query killed. Continuing normally.
    +--------+---------+--------+---------+----------+-----------+-----------------+---------------------+---------------------+--------------------------------------------------------------------------+-------------+-------------+-----------------+---------------------+-------+---------------------+------------+---------+---------+----------+---------------------+---------------------+------------+------------+
    10227 rows in set (1.42 sec)
    
     create index idx_siteid_docstatus_pubtime on wcmchnldoc(siteid,docstatus,DOCPUBTIME);
    
    MariaDB [trswcmtest]> explain select SITEID,RECID,CHNLID,DOCID,DOCORDER,DOCSTATUS,CRUSER,CRTIME,DOCPUBTIME,DOCPUBURL,DOCORDERPRI,INVALIDTIME,OPERUSER,OPERTIME,MODAL,DOCRELTIME,DOCCHANNEL,DOCFLAG,DOCKIND,'zjrb_mlf',now(),now(),'xuguozheng','xuguozheng' from wcmchnldoc where DOCPUBTIME >= date_add(STR_TO_DATE('2018-08-14', '%Y-%m-%d'), interval -14 day) and DOCPUBTIME <= STR_TO_DATE('2018-08-14', '%Y-%m-%d') and SITEID=198 and DOCSTATUS=10;
    +------+-------------+------------+-------+---------------------------------------------------------------+------------------------------+---------+------+-------+-----------------------+
    | id   | select_type | table      | type  | possible_keys                                                 | key                          | key_len | ref  | rows  | Extra                 |
    +------+-------------+------------+-------+---------------------------------------------------------------+------------------------------+---------+------+-------+-----------------------+
    |    1 | SIMPLE      | wcmchnldoc | range | IX_WCMChnlDoc_SiteId_OriginDocId,idx_siteid_docstatus_pubtime | idx_siteid_docstatus_pubtime | 14      | NULL | 20312 | Using index condition |
    +------+-------------+------------+-------+---------------------------------------------------------------+------------------------------+---------+------+-------+-----------------------+
    1 row in set (0.00 sec)
    
    ...
            | 2018-08-07 11:01:23 |     1 | 2018-08-03 07:41:44 |      11494 |    NULL |       6 | zjrb_mlf | 2018-08-14 18:02:01 | 2018-08-14 18:02:01 | xuguozheng | xuguozheng |
    Ctrl-C -- query killed. Continuing normally.
    +--------+---------+--------+---------+----------+-----------+-----------------+---------------------+---------------------+--------------------------------------------------------------------------+-------------+-------------+-----------------+---------------------+-------+---------------------+------------+---------+---------+----------+---------------------+---------------------+------------+------------+
    10227 rows in set (0.05 sec)

    案例3(关联字段类型不一致)

    17:06:51 root@mysql3306.sock [xucl]>show create table table_aG
    *************************** 1. row ***************************
           Table: table_a
    Create Table: CREATE TABLE `table_a` (
      `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增ID',
      `code` varchar(20) NOT NULL COMMENT '编码',
      PRIMARY KEY (`id`),
      KEY `code` (`code`)
    ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8
    1 row in set (0.00 sec)
    
    17:07:26 root@mysql3306.sock [xucl]>show create table table_bG
    *************************** 1. row ***************************
           Table: table_b
    Create Table: CREATE TABLE `table_b` (
      `code` int(10) unsigned NOT NULL COMMENT '编码',
      `name` varchar(20) NOT NULL COMMENT '名称',
      KEY `code` (`code`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8
    1 row in set (0.00 sec)
    
    17:07:28 root@mysql3306.sock [xucl]>select * from table_a;
    +----+------+
    | id | code |
    +----+------+
    |  1 | 1001 |
    |  5 | 1001 |
    |  3 | 1002 |
    |  6 | 1002 |
    |  2 | A001 |
    |  4 | B001 |
    +----+------+
    6 rows in set (0.00 sec)
    
    17:07:34 root@mysql3306.sock [xucl]>select * from table_b;
    +------+---------+
    | code | name    |
    +------+---------+
    | 1001 | 测试1   |
    | 1002 | 测试2   |
    +------+---------+
    2 rows in set (0.00 sec)
    
    17:07:36 root@mysql3306.sock [xucl]>explain SELECT count(1) FROM `table_a` a LEFT JOIN table_b b ON a.code = b.code WHERE b.code =1001;
    +----+-------------+-------+------+---------------+------+---------+-------+------+------------------------------------------------+
    | id | select_type | table | type | possible_keys | key  | key_len | ref   | rows | Extra                                          |
    +----+-------------+-------+------+---------------+------+---------+-------+------+------------------------------------------------+
    |  1 | SIMPLE      | b     | ref  | code          | code | 4       | const |    1 | Using index                                    |
    |  1 | SIMPLE      | a     | ALL  | code          | NULL | NULL    | NULL  |    6 | Range checked for each record (index map: 0x2) |
    +----+-------------+-------+------+---------------+------+---------+-------+------+------------------------------------------------+
    2 rows in set (0.00 sec)
    
    17:07:38 root@mysql3306.sock [xucl]>explain SELECT count(1) FROM `table_a` a LEFT JOIN table_b b ON a.code = convert(b.code, char)
        -> WHERE b.code =1001;
    +----+-------------+-------+------+---------------+------+---------+-------+------+--------------------------+
    | id | select_type | table | type | possible_keys | key  | key_len | ref   | rows | Extra                    |
    +----+-------------+-------+------+---------------+------+---------+-------+------+--------------------------+
    |  1 | SIMPLE      | b     | ref  | code          | code | 4       | const |    1 | Using index              |
    |  1 | SIMPLE      | a     | ref  | code          | code | 62      | const |    2 | Using where; Using index |
    +----+-------------+-------+------+---------------+------+---------+-------+------+--------------------------+
    2 rows in set (0.00 sec)

    案例4(字符集类型不一致)

    17:25:11 root@mysql3306.sock [xucl]>show create table t1G
    *************************** 1. row ***************************
           Table: t1
    Create Table: CREATE TABLE `t1` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(20) DEFAULT NULL,
      `code` varchar(50) DEFAULT NULL,
      PRIMARY KEY (`id`),
      KEY `idx_code` (`code`),
      KEY `idx_name` (`name`)
    ) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8
    1 row in set (0.00 sec)
    
    17:25:20 root@mysql3306.sock [xucl]>show create table t2G
    *************************** 1. row ***************************
           Table: t2
    Create Table: CREATE TABLE `t2` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(20) DEFAULT NULL,
      `code` varchar(50) DEFAULT NULL,
      PRIMARY KEY (`id`),
      KEY `idx_code` (`code`),
      KEY `idx_name` (`name`)
    ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4
    1 row in set (0.00 sec)
    
    17:24:53 root@mysql3306.sock [xucl]>select * from t1;                                                                                                                                  
    +----+------+----------------------------------+
    | id | name | code                             |
    +----+------+----------------------------------+
    |  6 | aaaa | 0752b0e3c72d4f5c701728db8ea8a3f9 |
    |  7 | bbbb | 36d8147db18d55e64c8b5ea8679328b7 |
    |  8 | cccc | dc3bab5197eeb6b315204f0af563c961 |
    |  9 | dddd | 1bb4dc313a54e4c0ee04644d2a1fe900 |
    +----+------+----------------------------------+
    4 rows in set (0.00 sec)
    
    17:24:57 root@mysql3306.sock [xucl]>select * from t2;
    +----+------+----------------------------------+
    | id | name | code                             |
    +----+------+----------------------------------+
    |  6 | aaaa | bca3bc1eb999136d6e6f877d9accc918 |
    |  7 | bbbb | 77dd5d07ea1c458afd76c8a6d953cf0a |
    |  8 | cccc | 3ac617d1857444e5383f074c60af7efd |
    |  9 | dddd | 8a77a32a7e0825f7c8634226105c42e5 |
    | 10 | eeee | 0c7fc18b8995e9e31ca774b1312be035 |
    +----+------+----------------------------------+
    5 rows in set (0.00 sec)
    
    root@localhost [xucl]>desc select * from t2 left join t1 on t1.code = t2.code where t2.name = 'dddd';
    +----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+----------------------------------------------------+
    | id | select_type | table | partitions | type | possible_keys | key      | key_len | ref   | rows | filtered | Extra                                              |
    +----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+----------------------------------------------------+
    |  1 | SIMPLE      | t2    | NULL       | ref  | idx_name      | idx_name | 83      | const |    1 |   100.00 | NULL                                               |
    |  1 | SIMPLE      | t1    | NULL       | ALL  | NULL          | NULL     | NULL    | NULL  |    4 |   100.00 | Using where; Using join buffer (Block Nested Loop) |
    +----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+----------------------------------------------------+
    2 rows in set, 1 warning (0.00 sec)
    
    root@localhost [xucl]>show create table t3G
    *************************** 1. row ***************************
           Table: t3
    Create Table: CREATE TABLE `t3` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(20) DEFAULT NULL,
      `code` varchar(50) DEFAULT NULL,
      PRIMARY KEY (`id`),
      KEY `idx_code` (`code`),
      KEY `idx_name` (`name`)
    ) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8
    1 row in set (0.00 sec)
    root@localhost [xucl]>select * from t3;
    +----+------+----------------------------------+
    | id | name | code                             |
    +----+------+----------------------------------+
    | 11 | aaaa | bca3bc1eb999136d6e6f877d9accc918 |
    | 12 | bbbb | 77dd5d07ea1c458afd76c8a6d953cf0a |
    | 13 | cccc | 3ac617d1857444e5383f074c60af7efd |
    | 14 | dddd | 8a77a32a7e0825f7c8634226105c42e5 |
    | 15 | eeee | 0c7fc18b8995e9e31ca774b1312be035 |
    +----+------+----------------------------------+
    5 rows in set (0.00 sec)
    root@localhost [xucl]>desc select * from t3 left join t1 on t1.code = t3.code where t3.name = 'dddd';
    +----+-------------+-------+------------+------+---------------+----------+---------+--------------+------+----------+-------+
    | id | select_type | table | partitions | type | possible_keys | key      | key_len | ref          | rows | filtered | Extra |
    +----+-------------+-------+------------+------+---------------+----------+---------+--------------+------+----------+-------+
    |  1 | SIMPLE      | t3    | NULL       | ref  | idx_name      | idx_name | 63      | const        |    1 |   100.00 | NULL  |
    |  1 | SIMPLE      | t1    | NULL       | ref  | idx_code      | idx_code | 153     | xucl.t3.code |    1 |   100.00 | NULL  |
    +----+-------------+-------+------------+------+---------------+----------+---------+--------------+------+----------+-------+
    2 rows in set, 1 warning (0.00 sec)
    螃蟹在剥我的壳,笔记本在写我,漫天的我落在枫叶上雪花上,而你在想我。 --章怀柔
  • 相关阅读:
    sys模块
    反射
    动态导入模块
    类的静态属性
    多态
    继承
    组合
    linux系统各个子目录的内容
    mysql安装
    Docker 数据卷操作
  • 原文地址:https://www.cnblogs.com/lovezhr/p/14703589.html
Copyright © 2011-2022 走看看