目录

  • 几个基础概念

  • 索引的作用

  • 索引种类

  • 索引为何不可用

  • 索引原则与误区

  • 执行计划

  • 测试案例

几个基础概念

用户

api@’192.168.1.1’
api@’192.168.1.%’
api@’%’

权限

应用程序:增删改查
用户:只读->从库
其他操作:自动化运维平台

索引的作用

  • 提高查询效率

  • 消除数据分组/排序

  • 避免”回表”查询

  • 优化聚合查询

  • 用于多表JOIN关联查询

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

  • InnoDB行锁实现

  • 增加I/O成本

  • 增加磁盘空间

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

索引种类

  • BTREE,InnoDB & MyISAM

  • Fractal TREE,TokuDB

  • HASH HEAP NDB InnoDB AHI

  • RTREE

  • FULLTEXT

索引讲解

  • 聚集索引

  • 主键索引

  • 唯一索引

  • 联合索引

  • 覆盖索引

  • 前缀索引

聚集索引

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

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

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

  • MyISAM没有聚集索引的概念

  • 聚集索引优先选择列
  1. INT/BIGINT;

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

  • 不建议的聚集索引
  1. 修改频繁的列;

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

  • InnoDB聚集索引选择次序原则
  1. 显示声明的主键;

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

  3. ROWID(实例级,6bytes)

【MySQL】MySQL索引 - 图1

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

  1. mysql> create table t(id int auto_increment,name varchar(10),primary key(id));
  2. Query OK, 0 rows affected (0.02 sec)
  1. TABLE: name test/t, id 23, flags 1, columns 5, indexes 2, appr.rows 0
  2. 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;
  3. INDEX: name PRIMARY, id 25, fields 1/4, uniq 1, type 3
  4. root page 3, appr.key vals 0, leaf pages 1, size pages 1
  5. FIELDS: id DB_TRX_ID DB_ROLL_PTR name
  6. INDEX: name idx_name, id 26, fields 1/2, uniq 2, type 0
  7. root page 4, appr.key vals 0, leaf pages 1, size pages 1
  8. FIELDS: name id

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

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

  1. mysql> create table t1(id int ,name varchar(10) not null,unique key idx_name(name));
  2. Query OK, 0 rows affected (0.01 sec)
  1. TABLE: name test/t1, id 25, flags 1, columns 5, indexes 1, appr.rows 0
  2. 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;
  3. INDEX: name idx_name, id 29, fields 1/4, uniq 1, type 3
  4. root page 3, appr.key vals 0, leaf pages 1, size pages 1
  5. FIELDS: name DB_TRX_ID DB_ROLL_PTR id

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

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

  1. mysql> create table t2(id int ,name varchar(10),key idx_name(name));
  2. Query OK, 0 rows affected (0.02 sec)
  1. TABLE: name test/t2, id 26, flags 1, columns 5, indexes 2, appr.rows 0
  2. 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;
  3. INDEX: name GEN_CLUST_INDEX, id 30, fields 0/5, uniq 1, type 1
  4. root page 3, appr.key vals 0, leaf pages 1, size pages 1
  5. FIELDS: DB_ROW_ID DB_TRX_ID DB_ROLL_PTR id name
  6. INDEX: name idx_name, id 31, fields 1/2, uniq 2, type 0
  7. root page 4, appr.key vals 0, leaf pages 1, size pages 1
  8. FIELDS: name DB_ROW_ID

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

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

  1. 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));
  2. Query OK, 0 rows affected (0.02 sec)
  1. TABLE: name test/t3, id 27, flags 1, columns 6, indexes 3, appr.rows 0
  2. 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;
  3. INDEX: name PRIMARY, id 32, fields 1/5, uniq 1, type 3
  4. root page 3, appr.key vals 0, leaf pages 1, size pages 1
  5. FIELDS: id DB_TRX_ID DB_ROLL_PTR name1 name2
  6. INDEX: name idx_name1, id 33, fields 1/2, uniq 1, type 2
  7. root page 4, appr.key vals 0, leaf pages 1, size pages 1
  8. FIELDS: name1 id
  9. INDEX: name idx_name2, id 34, fields 1/2, uniq 2, type 0
  10. root page 5, appr.key vals 0, leaf pages 1, size pages 1
  11. FIELDS: name2 id

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

主键索引

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

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

  • 保证数据的完整性;

  • 加快数据的操作速度;

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

  • 主键选择建议
  1. 对业务透明,无意义,免受业务变化的影响;

  2. 很少修改和删除

  3. 最好是自增;

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

  • 糟糕的主键选择:
  1. UUID

  2. char/varchar

辅助索引

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

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

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

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

【MySQL】MySQL索引 - 图2

唯一索引

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

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

  • 其他不同的方面:

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

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

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

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

联合索引

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

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

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

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

  • 联合索引建议

A.WHERE条件中,经常同时出现的列放在联合索引中
B.把选择性(过滤性/基数)大的列放在联合索引的最左边

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

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

示例

  1. root@localhost [xucl]>show create table test\G
  2. *************************** 1. row ***************************
  3. Table: test
  4. Create Table: CREATE TABLE `test` (
  5. `id` int(11) NOT NULL AUTO_INCREMENT,
  6. `a` varchar(10) DEFAULT NULL,
  7. `b` varchar(10) DEFAULT NULL,
  8. `c` varchar(10) DEFAULT NULL,
  9. PRIMARY KEY (`id`),
  10. KEY `idx_a_b_c` (`a`,`b`,`c`)
  11. ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8
  12. 1 row in set (0.00 sec)
  13. root@localhost [xucl]>explain select * from test where a='a';
  14. +----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------------+
  15. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  16. +----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------------+
  17. | 1 | SIMPLE | test | NULL | ref | idx_a_b_c | idx_a_b_c | 33 | const | 5 | 100.00 | Using index |
  18. +----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------------+
  19. 1 row in set, 1 warning (0.00 sec)
  20. root@localhost [xucl]>explain select * from test where a='a' and b='b';
  21. +----+-------------+-------+------------+------+---------------+-----------+---------+-------------+------+----------+-------------+
  22. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  23. +----+-------------+-------+------------+------+---------------+-----------+---------+-------------+------+----------+-------------+
  24. | 1 | SIMPLE | test | NULL | ref | idx_a_b_c | idx_a_b_c | 66 | const,const | 2 | 100.00 | Using index |
  25. +----+-------------+-------+------------+------+---------------+-----------+---------+-------------+------+----------+-------------+
  26. 1 row in set, 1 warning (0.00 sec)
  27. root@localhost [xucl]>explain select * from test where a='a' and b='b' and c='c';
  28. +----+-------------+-------+------------+------+---------------+-----------+---------+-------------------+------+----------+-------------+
  29. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  30. +----+-------------+-------+------------+------+---------------+-----------+---------+-------------------+------+----------+-------------+
  31. | 1 | SIMPLE | test | NULL | ref | idx_a_b_c | idx_a_b_c | 99 | const,const,const | 1 | 100.00 | Using index |
  32. +----+-------------+-------+------------+------+---------------+-----------+---------+-------------------+------+----------+-------------+
  33. 1 row in set, 1 warning (0.00 sec)

覆盖索引

选择的列+where就可以覆盖索引
执行计划里面type=index,表示full index scan,
extra中显示using index表示覆盖索引

示例

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

前缀索引

  • 部分索引的原因

A.char/varchar太长全部做索引的话,效率太差,存在浪费
B.或者blob/text类型不能整列作为索引列,因此需要使用前缀索引

  • 部分索引选择建议

A.统计平均值
B.满足80%~90%覆盖度就够

  • 缺点

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

示例1

  1. root@localhost [xucl]>create table t_text(id int auto_increment primary key,url text);
  2. Query OK, 0 rows affected (0.02 sec)
  3. root@localhost [xucl]>select * from t_text\G
  4. *************************** 1. row ***************************
  5. id: 1
  6. 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
  7. 1 row in set (0.00 sec)
  1. root@localhost [xucl]>select length(url) from t_text;
  2. +-------------+
  3. | length(url) |
  4. +-------------+
  5. | 1855 |
  6. +-------------+
  7. 1 row in set (0.00 sec)
  1. root@localhost [xucl]>create index idx_url on t_text(url);
  2. ERROR 1170 (42000): BLOB/TEXT column 'url' used in key specification without a key length
  1. root@localhost [xucl]>create index idx_url on t_text(url(255));
  2. Query OK, 0 rows affected (0.03 sec)
  3. Records: 0 Duplicates: 0 Warnings: 0
  4. root@localhost [xucl]>show index from t_text;
  5. +--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
  6. | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
  7. +--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
  8. | t_text | 0 | PRIMARY | 1 | id | A | 1 | NULL | NULL | | BTREE | | |
  9. | t_text | 1 | idx_url | 1 | url | A | 1 | 255 | NULL | YES | BTREE | | |
  10. +--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
  11. 2 rows in set (0.00 sec)

示例2

  1. root@localhost [xucl]>create table t_varchar(id int auto_increment primary key,url varchar(4000));
  2. Query OK, 0 rows affected (0.02 sec)
  3. root@localhost [xucl]>create index idx_url on t_varchar(url);
  4. ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes
  5. root@localhost [xucl]>create index idx_url on t_varchar(url(1000));
  6. Query OK, 0 rows affected (0.03 sec)
  7. Records: 0 Duplicates: 0 Warnings: 0
  8. root@localhost [xucl]>explain select * from t_varchar where url like 'http%';
  9. +----+-------------+-----------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
  10. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  11. +----+-------------+-----------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
  12. | 1 | SIMPLE | t_varchar | NULL | range | idx_url | idx_url | 3003 | NULL | 1 | 100.00 | Using where |
  13. +----+-------------+-----------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
  14. 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个

  1. root@localhost [xucl]>show create table wcmchnldoc\G
  2. *************************** 1. row ***************************
  3. Table: wcmchnldoc
  4. Create Table: CREATE TABLE `wcmchnldoc` (
  5. `CHNLID` int(11) NOT NULL,
  6. `DOCID` int(11) NOT NULL,
  7. `DOCORDER` int(11) NOT NULL DEFAULT '0',
  8. `DOCSTATUS` int(11) NOT NULL DEFAULT '0',
  9. `CRUSER` varchar(100) NOT NULL DEFAULT 'admin',
  10. ....
  11. PRIMARY KEY (`RECID`),
  12. KEY `IX_WCMCHNLDOC_CHNL_DOC` (`CHNLID`,`DOCID`) USING BTREE,
  13. KEY `IX_WCMCHNLDOC_CHNL_ORDER` (`CHNLID`,`DOCORDER`) USING BTREE,
  14. KEY `IX_WCMCHNLDOC_CRDEPT` (`CRDEPT`) USING BTREE,
  15. KEY `IX_WCMCHNLDOC_CRTIMEUDSCSDF` (`CRTIME`,`CRUSER`,`DOCSTATUS`,`CHNLID`,`SITEID`,`DOCFORM`) USING BTREE,
  16. KEY `IX_WCMCHNLDOC_CRTIMEUDSCSDO` (`CRTIME`,`CRUSER`,`DOCSTATUS`,`CHNLID`,`SITEID`,`DOCOUTUPID`) USING BTREE,
  17. KEY `IX_WCMCHNLDOC_CRTIMEUDSCSM` (`CRTIME`,`CRUSER`,`DOCSTATUS`,`CHNLID`,`SITEID`,`MODAL`) USING BTREE,
  18. KEY `IX_WCMCHNLDOC_CRUSER` (`CRUSER`) USING BTREE,
  19. KEY `IX_WCMCHNLDOC_DOCFIRSTPUBTIME` (`DOCFIRSTPUBTIME`) USING BTREE,
  20. KEY `IX_WCMCHNLDOC_DOCTYPE` (`DOCTYPE`) USING BTREE,
  21. KEY `IX_WCMCHNLDOC_DOCID_MODAL` (`DOCID`,`MODAL`) USING BTREE,
  22. KEY `IX_WCMChnlDoc_OriginDocId_SiteId_CrTime` (`OriginDocId`,`SITEID`,`CRTIME`) USING BTREE,
  23. KEY `IX_WCMChnlDoc_SiteId_OriginDocId` (`SITEID`,`OriginDocId`) USING BTREE,
  24. KEY `IX_WCMChnlDoc_CrUserStatus` (`DOCKIND`,`CRUSER`,`DOCSTATUS`),
  25. KEY `IX_WCMChnlDoc_SiteIdStatus` (`DOCKIND`,`SITEID`,`DOCSTATUS`),
  26. KEY `IX_WCMChnlDoc_PubTimeChnlStatus` (`DOCKIND`,`DOCPUBTIME`,`CHNLID`,`DOCSTATUS`),
  27. KEY `IX_WCMChnlDoc_CrUserSiteStatus` (`DOCKIND`,`CRUSER`,`SITEID`,`DOCSTATUS`),
  28. KEY `idx_DocId_SrcMetaDataId` (`DOCID`,`SrcMetaDataId`),
  29. KEY `idx_SrcMetaDataId` (`SrcMetaDataId`),
  30. KEY `idx_doc_chl_sta_pub` (`DOCKIND`,`CHNLID`,`DOCSTATUS`,`ISTIMINGPUBLISH`,`OPERTIME`),
  31. KEY `idx_chnlid_docstatus_dockind_docpubtime` (`CHNLID`,`DOCSTATUS`,`DOCKIND`,`DOCPUBTIME`)
  32. ) ENGINE=InnoDB DEFAULT CHARSET=utf8
  33. root@localhost [xucl]>show create table wcmchnldoc\G
  34. *************************** 1. row ***************************
  35. Table: wcmchnldoc
  36. Create Table: CREATE TABLE `wcmchnldoc` (
  37. `CHNLID` int(11) NOT NULL,
  38. `DOCID` int(11) NOT NULL,
  39. `DOCORDER` int(11) NOT NULL DEFAULT '0',
  40. `DOCSTATUS` int(11) NOT NULL DEFAULT '0',
  41. `CRUSER` varchar(100) NOT NULL DEFAULT 'admin',
  42. `CRTIME` datetime DEFAULT NULL,
  43. ....
  44. PRIMARY KEY (`id`),
  45. UNIQUE KEY `uk_recid` (`RECID`),
  46. KEY `idx_docpuburl_doctype` (`DOCPUBURL`,`DOCTYPE`)
  47. ) ENGINE=InnoDB AUTO_INCREMENT=7824427 DEFAULT CHARSET=utf8
  48. 1 row in set (0.00 sec)

大小对比

  1. MariaDB [information_schema]> select (sum(DATA_LENGTH)+sum(INDEX_LENGTH))/1024/1024/1024 from tables where table_name = 'wcmchnldoc';
  2. +-----------------------------------------------------+
  3. | (sum(DATA_LENGTH)+sum(INDEX_LENGTH))/1024/1024/1024 |
  4. +-----------------------------------------------------+
  5. | 7.618774414063 |
  6. +-----------------------------------------------------+
  7. 1 row in set (0.02 sec)
  8. root@localhost [xucl]>select (sum(DATA_LENGTH)+sum(INDEX_LENGTH))/1024/1024/1024 from information_schema.tables where table_name = 'wcmchnldoc';
  9. +-----------------------------------------------------+
  10. | (sum(DATA_LENGTH)+sum(INDEX_LENGTH))/1024/1024/1024 |
  11. +-----------------------------------------------------+
  12. | 1.877914428711 |
  13. +-----------------------------------------------------+
  14. 1 row in set (0.00 sec)

数据导入对比

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

140S VS 24S

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

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

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

  1. root@localhost [xucl]>show create table ttt\G
  2. *************************** 1. row ***************************
  3. Table: ttt
  4. Create Table: CREATE TABLE `ttt` (
  5. `id` int(11) NOT NULL AUTO_INCREMENT,
  6. `status` int(11) DEFAULT NULL,
  7. `chnnel_id` int(11) DEFAULT NULL,
  8. `docid` int(11) DEFAULT NULL,
  9. `remark` varchar(100) DEFAULT '',
  10. PRIMARY KEY (`id`),
  11. UNIQUE KEY `uk_docid` (`docid`),
  12. KEY `idx_status_chnnel_docid` (`status`,`chnnel_id`,`docid`)
  13. ) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8
  14. 1 row in set (0.00 sec)
  15. root@localhost [xucl]>select * from ttt;
  16. +-----+--------+-----------+-------+--------+
  17. | id | status | chnnel_id | docid | remark |
  18. +-----+--------+-----------+-------+--------+
  19. | 19 | 1 | 1 | 120 | |
  20. | 20 | 1 | 1 | 121 | |
  21. | 21 | 1 | 2 | 122 | |
  22. | 22 | 1 | 2 | 123 | |
  23. | 23 | 0 | 3 | 124 | |
  24. | 24 | 0 | 3 | 125 | |
  25. | 25 | 0 | 4 | 126 | |
  26. | 26 | 0 | 5 | 127 | |
  27. |
  28. ...
  29. | 99 | 1 | 1 | 201 | |
  30. | 100 | 1 | 1 | 202 | |
  31. | 101 | 1 | 2 | 203 | |
  32. | 102 | 1 | 2 | 204 | |
  33. | 103 | 0 | 3 | 205 | |
  34. | 104 | 0 | 3 | 206 | |
  35. | 105 | 0 | 4 | 207 | |
  36. | 106 | 0 | 5 | 208 | |
  37. | 107 | 1 | 1 | 209 | |
  38. | 108 | 1 | 1 | 210 | |
  39. | 109 | 1 | 2 | 211 | |
  40. | 110 | 1 | 2 | 212 | |
  41. | 111 | 0 | 3 | 213 | |
  42. | 112 | 0 | 3 | 214 | |
  43. | 113 | 0 | 4 | 215 | |
  44. | 114 | 0 | 5 | 216 | |
  45. | 115 | 1 | 1 | 217 | |
  46. | 116 | 1 | 1 | 218 | |
  47. | 117 | 1 | 2 | 219 | |
  48. | 118 | 1 | 2 | 220 | |
  49. | 119 | 0 | 3 | 221 | |
  50. | 120 | 0 | 3 | 222 | |
  51. | 121 | 0 | 4 | 223 | |
  52. | 122 | 0 | 5 | 224 | |
  53. +-----+--------+-----------+-------+--------+
  54. 103 rows in set (0.00 sec)
  55. root@localhost [xucl]>select count(distinct(status))/count(*),count(distinct(chnnel_id))/count(*),count(distinct(docid))/count(*) from ttt;
  56. +----------------------------------+-------------------------------------+---------------------------------+
  57. | count(distinct(status))/count(*) | count(distinct(chnnel_id))/count(*) | count(distinct(docid))/count(*) |
  58. +----------------------------------+-------------------------------------+---------------------------------+
  59. | 0.0194 | 0.0485 | 1.0000 |
  60. +----------------------------------+-------------------------------------+---------------------------------+
  61. 1 row in set (0.00 sec)
  62. root@localhost [xucl]>explain select * from ttt where status=1 and chnnel_id=2 and docid in (120,121,122,130);
  63. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
  64. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  65. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
  66. | 1 | SIMPLE | ttt | NULL | ALL | NULL | NULL | NULL | NULL | 8 | 12.50 | Using where |
  67. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
  68. 1 row in set, 1 warning (0.00 sec)
  69. root@localhost [xucl]>create index idx_status_chnnel_docid on ttt(status,chnnel_id,docid);
  70. Query OK, 0 rows affected (0.02 sec)
  71. Records: 0 Duplicates: 0 Warnings: 0
  72. root@localhost [xucl]>show index from ttt;
  73. +-------+------------+-------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
  74. | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
  75. +-------+------------+-------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
  76. | ttt | 0 | PRIMARY | 1 | id | A | 8 | NULL | NULL | | BTREE | | |
  77. | ttt | 0 | uk_docid | 1 | docid | A | 8 | NULL | NULL | YES | BTREE | | |
  78. | ttt | 1 | idx_status_chnnel_docid | 1 | status | A | 2 | NULL | NULL | YES | BTREE | | |
  79. | ttt | 1 | idx_status_chnnel_docid | 2 | chnnel_id | A | 5 | NULL | NULL | YES | BTREE | | |
  80. | ttt | 1 | idx_status_chnnel_docid | 3 | docid | A | 8 | NULL | NULL | YES | BTREE | | |
  81. +-------+------------+-------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
  82. 5 rows in set (0.00 sec)
  83. root@localhost [xucl]>explain select * from ttt where status=1 and chnnel_id=2 and docid in (120,121,122,130);
  84. +----+-------------+-------+------------+-------+----------------------------------+-------------------------+---------+------+------+----------+-----------------------+
  85. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  86. +----+-------------+-------+------------+-------+----------------------------------+-------------------------+---------+------+------+----------+-----------------------+
  87. | 1 | SIMPLE | ttt | NULL | range | uk_docid,idx_status_chnnel_docid | idx_status_chnnel_docid | 15 | NULL | 4 | 100.00 | Using index condition |
  88. +----+-------------+-------+------------+-------+----------------------------------+-------------------------+---------+------+------+----------+-----------------------+
  89. 1 row in set, 1 warning (0.00 sec)
  90. #假如有如下SQL如何能够利用到该索引呢?
  91. root@localhost [xucl]>explain select * from ttt where chnnel_id=2 and docid in (120,121,122,130);
  92. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
  93. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  94. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
  95. | 1 | SIMPLE | ttt | NULL | ALL | NULL | NULL | NULL | NULL | 103 | 4.00 | Using where |
  96. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
  97. 1 row in set, 1 warning (0.00 sec)
  98. root@localhost [xucl]>explain select * from ttt where status in (0,1) and chnnel_id=2 and docid in (120,121,122,130);
  99. +----+-------------+-------+------------+-------+-------------------------+-------------------------+---------+------+------+----------+-----------------------+
  100. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  101. +----+-------------+-------+------------+-------+-------------------------+-------------------------+---------+------+------+----------+-----------------------+
  102. | 1 | SIMPLE | ttt | NULL | range | idx_status_chnnel_docid | idx_status_chnnel_docid | 15 | NULL | 8 | 100.00 | Using index condition |
  103. +----+-------------+-------+------------+-------+-------------------------+-------------------------+---------+------+------+----------+-----------------------+
  104. 1 row in set, 1 warning (0.00 sec)

原则5:default ‘’与default null

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

  1. root@localhost [xucl]>show create table test\G
  2. *************************** 1. row ***************************
  3. Table: test
  4. Create Table: CREATE TABLE `test` (
  5. `id` int(11) NOT NULL AUTO_INCREMENT,
  6. `a` varchar(10) DEFAULT NULL,
  7. `b` varchar(10) DEFAULT NULL,
  8. `c` varchar(10) DEFAULT NULL,
  9. PRIMARY KEY (`id`),
  10. KEY `idx_a_b_c` (`a`,`b`,`c`)
  11. ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8
  12. 1 row in set (0.00 sec)
  13. root@localhost [xucl]>select * from test where a is not null;
  14. +----+------+------+------+
  15. | id | a | b | c |
  16. +----+------+------+------+
  17. | 2 | a | a | |
  18. | 3 | a | a | d |
  19. | 1 | a | b | c |
  20. | 4 | a | b | d |
  21. | 5 | a | e | d |
  22. | 6 | b | e | d |
  23. | 7 | e | e | d |
  24. | 8 | g | e | d |
  25. | 9 | h | e | d |
  26. | 10 | h | i | d |
  27. +----+------+------+------+
  28. 10 rows in set (0.00 sec)
  29. root@localhost [xucl]>desc select * from test where a !='a';
  30. +----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+--------------------------+
  31. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  32. +----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+--------------------------+
  33. | 1 | SIMPLE | test | NULL | range | idx_a_b_c | idx_a_b_c | 33 | NULL | 6 | 100.00 | Using where; Using index |
  34. +----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+--------------------------+
  35. 1 row in set, 1 warning (0.00 sec)

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

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

执行计划

示例

  1. 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;
  2. +----+-------------+--------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
  3. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  4. +----+-------------+--------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
  5. | 1 | SIMPLE | wcmchnldoc0_ | NULL | ALL | NULL | NULL | NULL | NULL | 7531425 | 9.00 | Using where |
  6. +----+-------------+--------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
  7. 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)

  1. root@localhost [xucl]>show create table wcmchnldoc\G
  2. *************************** 1. row ***************************
  3. Table: wcmchnldoc
  4. Create Table: CREATE TABLE `wcmchnldoc` (
  5. `CHNLID` int(11) NOT NULL,
  6. `DOCID` int(11) NOT NULL,
  7. `DOCORDER` int(11) NOT NULL DEFAULT '0',
  8. `DOCSTATUS` int(11) NOT NULL DEFAULT '0',
  9. `CRUSER` varchar(100) NOT NULL DEFAULT 'admin',
  10. `CRTIME` datetime DEFAULT NULL,
  11. `DOCPUBTIME` datetime DEFAULT NULL,
  12. `DOCPUBURL` varchar(300) DEFAULT NULL,
  13. `RECID` int(11) NOT NULL,
  14. `DOCORDERPRI` int(11) NOT NULL DEFAULT '0',
  15. `INVALIDTIME` datetime DEFAULT NULL,
  16. `OPERUSER` varchar(50) DEFAULT NULL,
  17. `OPERTIME` datetime DEFAULT NULL,
  18. `MODAL` int(11) DEFAULT '1',
  19. `DOCRELTIME` datetime DEFAULT NULL,
  20. `DOCCHANNEL` int(11) DEFAULT NULL,
  21. `DOCFLAG` int(11) DEFAULT NULL,
  22. `DOCKIND` int(11) DEFAULT '0',
  23. `SITEID` int(11) NOT NULL DEFAULT '0',
  24. `SRCSITEID` int(11) NOT NULL DEFAULT '0',
  25. `DOCFIRSTPUBTIME` datetime DEFAULT NULL,
  26. `NODEID` int(11) DEFAULT '0',
  27. `CRDEPT` varchar(200) DEFAULT NULL,
  28. `DOCOUTUPID` int(11) DEFAULT '0',
  29. `DOCFORM` int(11) DEFAULT '0',
  30. `DOCLEVEL` int(11) DEFAULT NULL,
  31. `attachpic` smallint(6) DEFAULT NULL,
  32. `POSCHNLID` int(11) DEFAULT '0',
  33. `ISPUSHTOPCHNL` int(2) DEFAULT '0',
  34. `HIDDEN` int(2) DEFAULT '0',
  35. `DOCTYPE` int(2) DEFAULT '0',
  36. `ISTIMINGPUBLISH` int(2) DEFAULT '0',
  37. `GDORDER` int(2) DEFAULT NULL,
  38. `setTopInfo` varchar(100) DEFAULT NULL,
  39. `OriginDocId` int(9) DEFAULT NULL,
  40. `ATTACHVIDEO` int(2) DEFAULT '0',
  41. `ATTACHAUDIO` int(2) DEFAULT '0',
  42. `SrcMetaDataId` int(11) DEFAULT NULL,
  43. `pubUser` varchar(50) DEFAULT NULL,
  44. `mrsFlag` int(2) DEFAULT NULL,
  45. `timingPubUser` varchar(50) DEFAULT NULL,
  46. `isTransmit` int(2) DEFAULT NULL,
  47. `TIMINGPUBUSERDEPT` varchar(200) DEFAULT NULL,
  48. `PUBUSERDEPT` varchar(200) DEFAULT NULL,
  49. `DocOldStatus` int(11) DEFAULT '0',
  50. `isZhengShen` int(2) DEFAULT '0',
  51. `ClientExamine` int(2) DEFAULT '0',
  52. `srcChannelId` int(11) DEFAULT NULL,
  53. PRIMARY KEY (`RECID`),
  54. KEY `IX_WCMCHNLDOC_CHNL_DOC` (`CHNLID`,`DOCID`) USING BTREE,
  55. KEY `IX_WCMCHNLDOC_CHNL_ORDER` (`CHNLID`,`DOCORDER`) USING BTREE,
  56. KEY `IX_WCMCHNLDOC_CRDEPT` (`CRDEPT`) USING BTREE,
  57. KEY `IX_WCMCHNLDOC_CRTIMEUDSCSDF` (`CRTIME`,`CRUSER`,`DOCSTATUS`,`CHNLID`,`SITEID`,`DOCFORM`) USING BTREE,
  58. KEY `IX_WCMCHNLDOC_CRTIMEUDSCSDO` (`CRTIME`,`CRUSER`,`DOCSTATUS`,`CHNLID`,`SITEID`,`DOCOUTUPID`) USING BTREE,
  59. KEY `IX_WCMCHNLDOC_CRTIMEUDSCSM` (`CRTIME`,`CRUSER`,`DOCSTATUS`,`CHNLID`,`SITEID`,`MODAL`) USING BTREE,
  60. KEY `IX_WCMCHNLDOC_CRUSER` (`CRUSER`) USING BTREE,
  61. KEY `IX_WCMCHNLDOC_DOCFIRSTPUBTIME` (`DOCFIRSTPUBTIME`) USING BTREE,
  62. KEY `IX_WCMCHNLDOC_DOCTYPE` (`DOCTYPE`) USING BTREE,
  63. KEY `IX_WCMCHNLDOC_DOCID_MODAL` (`DOCID`,`MODAL`) USING BTREE,
  64. KEY `IX_WCMChnlDoc_OriginDocId_SiteId_CrTime` (`OriginDocId`,`SITEID`,`CRTIME`) USING BTREE,
  65. KEY `IX_WCMChnlDoc_SiteId_OriginDocId` (`SITEID`,`OriginDocId`) USING BTREE,
  66. KEY `IX_WCMChnlDoc_CrUserStatus` (`DOCKIND`,`CRUSER`,`DOCSTATUS`),
  67. KEY `IX_WCMChnlDoc_SiteIdStatus` (`DOCKIND`,`SITEID`,`DOCSTATUS`),
  68. KEY `IX_WCMChnlDoc_PubTimeChnlStatus` (`DOCKIND`,`DOCPUBTIME`,`CHNLID`,`DOCSTATUS`),
  69. KEY `IX_WCMChnlDoc_CrUserSiteStatus` (`DOCKIND`,`CRUSER`,`SITEID`,`DOCSTATUS`),
  70. KEY `idx_DocId_SrcMetaDataId` (`DOCID`,`SrcMetaDataId`),
  71. KEY `idx_SrcMetaDataId` (`SrcMetaDataId`),
  72. KEY `idx_doc_chl_sta_pub` (`DOCKIND`,`CHNLID`,`DOCSTATUS`,`ISTIMINGPUBLISH`,`OPERTIME`),
  73. KEY `idx_chnlid_docstatus_dockind_docpubtime` (`CHNLID`,`DOCSTATUS`,`DOCKIND`,`DOCPUBTIME`)
  74. ) ENGINE=InnoDB DEFAULT CHARSET=utf8
  75. root@localhost [xucl]>SELECT
  76. -> wcmchnldoc0_.recid AS recid1_1_,
  77. -> wcmchnldoc0_.chnlid AS chnlid2_1_,
  78. -> wcmchnldoc0_.docfirstpubtime AS docfirst3_1_,
  79. -> wcmchnldoc0_.docid AS docid4_1_,
  80. -> wcmchnldoc0_.docpubtime AS docpubti5_1_,
  81. -> wcmchnldoc0_.docpuburl AS docpubur6_1_,
  82. -> wcmchnldoc0_.doctype AS doctype7_1_,
  83. -> wcmchnldoc0_.modal AS modal8_1_
  84. -> FROM
  85. -> wcmchnldoc wcmchnldoc0_
  86. -> WHERE
  87. -> wcmchnldoc0_.docpuburl = 'http://photo.zjol.com.cn/yuanchuang/201807/t20180721_7834159.shtml'
  88. -> AND wcmchnldoc0_.doctype <> 4;
  89. +-----------+------------+---------------------+-----------+---------------------+--------------------------------------------------------------------+-------------+-----------+
  90. | recid1_1_ | chnlid2_1_ | docfirst3_1_ | docid4_1_ | docpubti5_1_ | docpubur6_1_ | doctype7_1_ | modal8_1_ |
  91. +-----------+------------+---------------------+-----------+---------------------+--------------------------------------------------------------------+-------------+-----------+
  92. | 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 |
  93. +-----------+------------+---------------------+-----------+---------------------+--------------------------------------------------------------------+-------------+-----------+
  94. 1 row in set (50.47 sec)
  95. 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;
  96. +----+-------------+--------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
  97. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  98. +----+-------------+--------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
  99. | 1 | SIMPLE | wcmchnldoc0_ | NULL | ALL | NULL | NULL | NULL | NULL | 7531425 | 9.00 | Using where |
  100. +----+-------------+--------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
  101. 1 row in set, 1 warning (0.00 sec)
  102. 优化1:
  103. root@localhost [xucl]>show create table wcmchnldoc\G
  104. *************************** 1. row ***************************
  105. Table: wcmchnldoc
  106. Create Table: CREATE TABLE `wcmchnldoc` (
  107. `CHNLID` int(11) NOT NULL,
  108. `DOCID` int(11) NOT NULL,
  109. `DOCORDER` int(11) NOT NULL DEFAULT '0',
  110. `DOCSTATUS` int(11) NOT NULL DEFAULT '0',
  111. `CRUSER` varchar(100) NOT NULL DEFAULT 'admin',
  112. `CRTIME` datetime DEFAULT NULL,
  113. `DOCPUBTIME` datetime DEFAULT NULL,
  114. `DOCPUBURL` varchar(300) DEFAULT NULL,
  115. `RECID` int(11) NOT NULL,
  116. `DOCTYPE` int(2) DEFAULT '0',
  117. `id` int(11) NOT NULL AUTO_INCREMENT,
  118. PRIMARY KEY (`id`),
  119. UNIQUE KEY `uk_recid` (`RECID`),
  120. KEY `idx_docpuburl_doctype` (`DOCPUBURL`,`DOCTYPE`)
  121. ) ENGINE=InnoDB AUTO_INCREMENT=7824427 DEFAULT CHARSET=utf8
  122. 1 row in set (0.00 sec)
  123. 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;
  124. +-----------+------------+---------------------+-----------+---------------------+--------------------------------------------------------------------+-------------+-----------+
  125. | recid1_1_ | chnlid2_1_ | docfirst3_1_ | docid4_1_ | docpubti5_1_ | docpubur6_1_ | doctype7_1_ | modal8_1_ |
  126. +-----------+------------+---------------------+-----------+---------------------+--------------------------------------------------------------------+-------------+-----------+
  127. | 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 |
  128. +-----------+------------+---------------------+-----------+---------------------+--------------------------------------------------------------------+-------------+-----------+
  129. 1 row in set (0.00 sec)
  130. 优化2
  131. 增加列
  132. docpuburl_crc32
  133. 增加索引
  134. idx_crc32
  135. root@localhost [xucl]>show create table wcmchnldoc\G
  136. *************************** 1. row ***************************
  137. Table: wcmchnldoc
  138. Create Table: CREATE TABLE `wcmchnldoc` (
  139. `id` int(11) NOT NULL AUTO_INCREMENT,
  140. `DOCPUBURL` varchar(300) DEFAULT NULL,
  141. `RECID` int(11) NOT NULL,
  142. `DOCORDERPRI` int(11) NOT NULL DEFAULT '0',
  143. `INVALIDTIME` datetime DEFAULT NULL,
  144. `OPERUSER` varchar(50) DEFAULT NULL,
  145. `DOCTYPE` int(2) DEFAULT '0',
  146. `docpuburl_crc32` bigint(20) DEFAULT NULL,
  147. PRIMARY KEY (`id`),
  148. UNIQUE KEY `uk_recid` (`RECID`),
  149. KEY `idx_docpuburl_doctype` (`DOCPUBURL`,`DOCTYPE`),
  150. KEY `idx_crc32` (`docpuburl_crc32`)
  151. ) ENGINE=InnoDB AUTO_INCREMENT=7824427 DEFAULT CHARSET=utf8
  152. 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;
  153. +----+-------------+--------------+------------+------+---------------+-----------+---------+-------+------+----------+-------------+
  154. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  155. +----+-------------+--------------+------------+------+---------------+-----------+---------+-------+------+----------+-------------+
  156. | 1 | SIMPLE | wcmchnldoc0_ | NULL | ref | idx_crc32 | idx_crc32 | 9 | const | 2 | 90.00 | Using where |
  157. +----+-------------+--------------+------------+------+---------------+-----------+---------+-------+------+----------+-------------+
  158. 1 row in set, 1 warning (0.00 sec)
  159. 问题点:
  160. hash值重复
  161. 解决方法
  162. 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';
  163. +----+-------------+--------------+------------+------+---------------------------------+-----------+---------+-------+------+----------+-------------+
  164. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  165. +----+-------------+--------------+------------+------+---------------------------------+-----------+---------+-------+------+----------+-------------+
  166. | 1 | SIMPLE | wcmchnldoc0_ | NULL | ref | idx_docpuburl_doctype,idx_crc32 | idx_crc32 | 9 | const | 2 | 2.50 | Using where |
  167. +----+-------------+--------------+------------+------+---------------------------------+-----------+---------+-------+------+----------+-------------+
  168. 1 row in set, 1 warning (0.00 sec)

案例2(索引字段顺序)

  1. 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;
  2. +------+-------------+------------+------+----------------------------------+----------------------------------+---------+-------+---------+-------------+
  3. | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
  4. +------+-------------+------------+------+----------------------------------+----------------------------------+---------+-------+---------+-------------+
  5. | 1 | SIMPLE | wcmchnldoc | ref | IX_WCMChnlDoc_SiteId_OriginDocId | IX_WCMChnlDoc_SiteId_OriginDocId | 4 | const | 2362574 | Using where |
  6. +------+-------------+------------+------+----------------------------------+----------------------------------+---------+-------+---------+-------------+
  7. 1 row in set (0.00 sec)
  8. ....
  9. | 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 |
  10. Ctrl-C -- query killed. Continuing normally.
  11. +--------+---------+--------+---------+----------+-----------+-----------------+---------------------+---------------------+--------------------------------------------------------------------------+-------------+-------------+-----------------+---------------------+-------+---------------------+------------+---------+---------+----------+---------------------+---------------------+------------+------------+
  12. 10227 rows in set (1.42 sec)
  13. create index idx_siteid_docstatus_pubtime on wcmchnldoc(siteid,docstatus,DOCPUBTIME);
  14. 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;
  15. +------+-------------+------------+-------+---------------------------------------------------------------+------------------------------+---------+------+-------+-----------------------+
  16. | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
  17. +------+-------------+------------+-------+---------------------------------------------------------------+------------------------------+---------+------+-------+-----------------------+
  18. | 1 | SIMPLE | wcmchnldoc | range | IX_WCMChnlDoc_SiteId_OriginDocId,idx_siteid_docstatus_pubtime | idx_siteid_docstatus_pubtime | 14 | NULL | 20312 | Using index condition |
  19. +------+-------------+------------+-------+---------------------------------------------------------------+------------------------------+---------+------+-------+-----------------------+
  20. 1 row in set (0.00 sec)
  21. ...
  22. | 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 |
  23. Ctrl-C -- query killed. Continuing normally.
  24. +--------+---------+--------+---------+----------+-----------+-----------------+---------------------+---------------------+--------------------------------------------------------------------------+-------------+-------------+-----------------+---------------------+-------+---------------------+------------+---------+---------+----------+---------------------+---------------------+------------+------------+
  25. 10227 rows in set (0.05 sec)

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

  1. 17:06:51 root@mysql3306.sock [xucl]>show create table table_a\G
  2. *************************** 1. row ***************************
  3. Table: table_a
  4. Create Table: CREATE TABLE `table_a` (
  5. `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增ID',
  6. `code` varchar(20) NOT NULL COMMENT '编码',
  7. PRIMARY KEY (`id`),
  8. KEY `code` (`code`)
  9. ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8
  10. 1 row in set (0.00 sec)
  11. 17:07:26 root@mysql3306.sock [xucl]>show create table table_b\G
  12. *************************** 1. row ***************************
  13. Table: table_b
  14. Create Table: CREATE TABLE `table_b` (
  15. `code` int(10) unsigned NOT NULL COMMENT '编码',
  16. `name` varchar(20) NOT NULL COMMENT '名称',
  17. KEY `code` (`code`)
  18. ) ENGINE=InnoDB DEFAULT CHARSET=utf8
  19. 1 row in set (0.00 sec)
  20. 17:07:28 root@mysql3306.sock [xucl]>select * from table_a;
  21. +----+------+
  22. | id | code |
  23. +----+------+
  24. | 1 | 1001 |
  25. | 5 | 1001 |
  26. | 3 | 1002 |
  27. | 6 | 1002 |
  28. | 2 | A001 |
  29. | 4 | B001 |
  30. +----+------+
  31. 6 rows in set (0.00 sec)
  32. 17:07:34 root@mysql3306.sock [xucl]>select * from table_b;
  33. +------+---------+
  34. | code | name |
  35. +------+---------+
  36. | 1001 | 测试1 |
  37. | 1002 | 测试2 |
  38. +------+---------+
  39. 2 rows in set (0.00 sec)
  40. 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;
  41. +----+-------------+-------+------+---------------+------+---------+-------+------+------------------------------------------------+
  42. | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
  43. +----+-------------+-------+------+---------------+------+---------+-------+------+------------------------------------------------+
  44. | 1 | SIMPLE | b | ref | code | code | 4 | const | 1 | Using index |
  45. | 1 | SIMPLE | a | ALL | code | NULL | NULL | NULL | 6 | Range checked for each record (index map: 0x2) |
  46. +----+-------------+-------+------+---------------+------+---------+-------+------+------------------------------------------------+
  47. 2 rows in set (0.00 sec)
  48. 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)
  49. -> WHERE b.code =1001;
  50. +----+-------------+-------+------+---------------+------+---------+-------+------+--------------------------+
  51. | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
  52. +----+-------------+-------+------+---------------+------+---------+-------+------+--------------------------+
  53. | 1 | SIMPLE | b | ref | code | code | 4 | const | 1 | Using index |
  54. | 1 | SIMPLE | a | ref | code | code | 62 | const | 2 | Using where; Using index |
  55. +----+-------------+-------+------+---------------+------+---------+-------+------+--------------------------+
  56. 2 rows in set (0.00 sec)

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

  1. 17:25:11 root@mysql3306.sock [xucl]>show create table t1\G
  2. *************************** 1. row ***************************
  3. Table: t1
  4. Create Table: CREATE TABLE `t1` (
  5. `id` int(11) NOT NULL AUTO_INCREMENT,
  6. `name` varchar(20) DEFAULT NULL,
  7. `code` varchar(50) DEFAULT NULL,
  8. PRIMARY KEY (`id`),
  9. KEY `idx_code` (`code`),
  10. KEY `idx_name` (`name`)
  11. ) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8
  12. 1 row in set (0.00 sec)
  13. 17:25:20 root@mysql3306.sock [xucl]>show create table t2\G
  14. *************************** 1. row ***************************
  15. Table: t2
  16. Create Table: CREATE TABLE `t2` (
  17. `id` int(11) NOT NULL AUTO_INCREMENT,
  18. `name` varchar(20) DEFAULT NULL,
  19. `code` varchar(50) DEFAULT NULL,
  20. PRIMARY KEY (`id`),
  21. KEY `idx_code` (`code`),
  22. KEY `idx_name` (`name`)
  23. ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4
  24. 1 row in set (0.00 sec)
  25. 17:24:53 root@mysql3306.sock [xucl]>select * from t1;
  26. +----+------+----------------------------------+
  27. | id | name | code |
  28. +----+------+----------------------------------+
  29. | 6 | aaaa | 0752b0e3c72d4f5c701728db8ea8a3f9 |
  30. | 7 | bbbb | 36d8147db18d55e64c8b5ea8679328b7 |
  31. | 8 | cccc | dc3bab5197eeb6b315204f0af563c961 |
  32. | 9 | dddd | 1bb4dc313a54e4c0ee04644d2a1fe900 |
  33. +----+------+----------------------------------+
  34. 4 rows in set (0.00 sec)
  35. 17:24:57 root@mysql3306.sock [xucl]>select * from t2;
  36. +----+------+----------------------------------+
  37. | id | name | code |
  38. +----+------+----------------------------------+
  39. | 6 | aaaa | bca3bc1eb999136d6e6f877d9accc918 |
  40. | 7 | bbbb | 77dd5d07ea1c458afd76c8a6d953cf0a |
  41. | 8 | cccc | 3ac617d1857444e5383f074c60af7efd |
  42. | 9 | dddd | 8a77a32a7e0825f7c8634226105c42e5 |
  43. | 10 | eeee | 0c7fc18b8995e9e31ca774b1312be035 |
  44. +----+------+----------------------------------+
  45. 5 rows in set (0.00 sec)
  46. root@localhost [xucl]>desc select * from t2 left join t1 on t1.code = t2.code where t2.name = 'dddd';
  47. +----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+----------------------------------------------------+
  48. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  49. +----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+----------------------------------------------------+
  50. | 1 | SIMPLE | t2 | NULL | ref | idx_name | idx_name | 83 | const | 1 | 100.00 | NULL |
  51. | 1 | SIMPLE | t1 | NULL | ALL | NULL | NULL | NULL | NULL | 4 | 100.00 | Using where; Using join buffer (Block Nested Loop) |
  52. +----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+----------------------------------------------------+
  53. 2 rows in set, 1 warning (0.00 sec)
  54. root@localhost [xucl]>show create table t3\G
  55. *************************** 1. row ***************************
  56. Table: t3
  57. Create Table: CREATE TABLE `t3` (
  58. `id` int(11) NOT NULL AUTO_INCREMENT,
  59. `name` varchar(20) DEFAULT NULL,
  60. `code` varchar(50) DEFAULT NULL,
  61. PRIMARY KEY (`id`),
  62. KEY `idx_code` (`code`),
  63. KEY `idx_name` (`name`)
  64. ) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8
  65. 1 row in set (0.00 sec)
  66. root@localhost [xucl]>select * from t3;
  67. +----+------+----------------------------------+
  68. | id | name | code |
  69. +----+------+----------------------------------+
  70. | 11 | aaaa | bca3bc1eb999136d6e6f877d9accc918 |
  71. | 12 | bbbb | 77dd5d07ea1c458afd76c8a6d953cf0a |
  72. | 13 | cccc | 3ac617d1857444e5383f074c60af7efd |
  73. | 14 | dddd | 8a77a32a7e0825f7c8634226105c42e5 |
  74. | 15 | eeee | 0c7fc18b8995e9e31ca774b1312be035 |
  75. +----+------+----------------------------------+
  76. 5 rows in set (0.00 sec)
  77. root@localhost [xucl]>desc select * from t3 left join t1 on t1.code = t3.code where t3.name = 'dddd';
  78. +----+-------------+-------+------------+------+---------------+----------+---------+--------------+------+----------+-------+
  79. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  80. +----+-------------+-------+------------+------+---------------+----------+---------+--------------+------+----------+-------+
  81. | 1 | SIMPLE | t3 | NULL | ref | idx_name | idx_name | 63 | const | 1 | 100.00 | NULL |
  82. | 1 | SIMPLE | t1 | NULL | ref | idx_code | idx_code | 153 | xucl.t3.code | 1 | 100.00 | NULL |
  83. +----+-------------+-------+------------+------+---------------+----------+---------+--------------+------+----------+-------+
  84. 2 rows in set, 1 warning (0.00 sec)