mysql status 索引,MySQL 索引优化

多表连接JOIN 语句应尽可能减少 NestedLoop 次数,即永远用小结果集驱动大结果集;

优先优化 NestedLoop 内层循环;

保证 JOIN 语句中被驱动表上的条件字段已经被索引;

不能保证 JOIN 语句中被驱动表上的条件字段已经被索引且内存资源充足的情况下可以加大 JOIN BUFFER 的设置。

双表连接

左连接时给右表条件字段加索引,右连接时给左表条件字段加索引。EXPLAIN SELECT * FROM `member` `m` LEFT JOIN `article` `a` ON `m`.`status` = `a`.`status`;

ef7f443edce5637b35d469cab45eebbe.png# 给左表的字段创建索引

# 左连接时左表中符合的数据都存在再加索引也没有效果

CREATE INDEX `idx_member_status` ON `member` (`status`);

EXPLAIN SELECT * FROM `member` `m` LEFT JOIN `article` `a` ON `m`.`status` = `a`.`status`;

2d1fa1d59d6668b998d5a228a46b8853.png# 给右表的字段创建索引

# 显然左连接时给右表条件字段加索引比较好

# 同理右连接时应该左表条件字段加索引

DROP INDEX `idx_member_status` ON `member`;

CREATE INDEX `idx_article_status` ON `article` (`status`);

EXPLAIN SELECT * FROM `member` `m` LEFT JOIN `article` `a` ON `m`.`status` = `a`.`status`;

9cd379ed0a8b8454ed8c90bbfb0b9874.png

三表连接

多表的左连接应给所有右表条件字段建立索引。# 清除之前的索引

DROP INDEX `idx_article_status` ON `article`;

EXPLAIN SELECT * FROM `member` `m` LEFT JOIN `article` `a` ON `m`.`status` = `a`.`status` LEFT JOIN `openid` `o` ON `a`.`status` = `o`.`status`;

14c6af99723725c50ca5494bb6dafbbf.png# 所有右表字段创建索引

CREATE INDEX `idx_article_status` ON `article` (`status`);

CREATE INDEX `idx_openid_status` ON `openid` (`status`);

EXPLAIN SELECT * FROM `member` `m` LEFT JOIN `article` `a` ON `m`.`status` = `a`.`status` LEFT JOIN `openid` `o` ON `a`.`status` = `o`.`status`;

778b7f1a396d3e0fa7084348c5722cdb.png

复合索引

复合索引应按序使用且不能跳过中间的列,如有索引 idx_name_status_email,如果查询时只使用到了 status 和 email 或者 name 和 email 则该索引不会生效。EXPLAIN SELECT `id` FROM `member` WHERE `status` = 0 AND `gender` = 0 AND `ip` = '';

0bf3f13e8f82711b2d9e1bf8f50ceaa2.png# 创建索引

CREATE INDEX `idx_status_gender_ip` ON `member` (`status`, `gender`, `ip`);

# 正确使用索引

EXPLAIN SELECT `id` FROM `member` WHERE `status` = 0 AND `gender` = '0';

2cf5c6a47d0be0ceb9679d6387e4ed62.png# ref 只有一个 const

# gender 为 CHAR 类型

# 查询时字符串不加单引号索引失效,复合索引只用了一部分

EXPLAIN SELECT `id` FROM `member` WHERE `status` = 0 AND `gender` = 0;

# 查询时未从左至右连续的使用索引,复合索引只用了一部分

EXPLAIN SELECT `id` FROM `member` WHERE `status` = 0 AND `ip` = '';

aa1682a81a3a884b01d1fadd7f7a92f4.png# ref 为 NULL

# 未按序使用索引

EXPLAIN SELECT `id` FROM `member` WHERE `gender` = '0' AND `ip` = '';

3f3283397af2d42ace12f2af7dbeb919.png

尽可能使用等值匹配,在结果集相同的情况下应减少不必要的 WHERE 条件。# 假设 ip = '' 不对结果集产生影响,更多的不必要条件增加了 key_len

EXPLAIN SELECT `id` FROM `member` WHERE `status` = 0 AND `gender` = '0' AND `ip` = '';

90143eb4f633d1a7bb2bf27c40befe0f.png

为 WHERE、ORDER BY、GROUP BY 字段创建复合索引。

存储引擎不使用复合索引中范围条件右边的列,案例:# 清除之前的索引

DROP INDEX `idx_article_status` ON `article` (`status`);

EXPLAIN SELECT `id`, `member_id` FROM `article` WHERE `create` > '2019-10-01' AND `status` = 0 ORDER BY `category_id` DESC LIMIT 1;

03c6cbb20e3d11f9804206fc51294b39.pngCREATE INDEX `idx_mid_status_cid` ON `article` (`member_id`, `status`, `category_id`);

# 由于 status 是范围比较,复合索引只用到了 member_id 和 status 字段

# category_id 未使用到索引而出现 Using filesort

EXPLAIN SELECT `id`, `member_id` FROM `article` WHERE `member_id` = 2 AND `status` 

2507d425a58e5dff622250df789ad9e4.png# 由 key_len 可知,复合索引只用到了 member_id 和 status 字段

# key_len 显示在索引中查询的字段长度,用于排序的字段不计算在其中

# 索引的作用:查询和排序

EXPLAIN SELECT `id`, `member_id` FROM `article` WHERE `member_id` = 2 AND `category_id` = 2 ORDER BY `status`;

# 复合索引用到了所有字段

# member_id 用于查询

# status 和 category_id 用于排序

EXPLAIN SELECT `id`, `member_id` FROM `article` WHERE `member_id` = 2 ORDER BY `status`, `category_id`;

2a2a902d3d157c0de68adc9dfa18bb29.png# 将排序中的 status 和 category_id 位置对调

# 排序不再使用索引,会出现 Using filesort

EXPLAIN SELECT `id`, `member_id` FROM `article` WHERE `member_id` = 2 ORDER BY `category_id`, `status`;

# 降序也将会导致  Using filesort

EXPLAIN SELECT `id`, `member_id` FROM `article` WHERE `member_id` = 2 ORDER BY `status`, `category_id` DESC;

# GROUP BY 如此操作还有可能产生临时表

05ffc96823a5bb88e12ae5529acb1813.png# 将排序中的 status 和 category_id 位置对调

# 由于 status 使用了索引故不会出现 Using filesort

EXPLAIN SELECT `id`, `member_id` FROM `article` WHERE `member_id` = 2 AND `status` = 0 ORDER BY `category_id`, `status`;

# GROUP BY 实际上是先排序在分组

EXPLAIN SELECT `id`, `member_id` FROM `article` WHERE `member_id` = 2 AND `status` = 0 GROUP BY `category_id`, `status`;

8b76e43579a42f8e8405dab6a121f7dd.png# 由 key_len 可知,复合索引的所有字段全部用到

EXPLAIN SELECT `id`, `member_id` FROM `article` WHERE `member_id` = 2 AND `status` = 0 AND `category_id` > 3;

e7bc85d246a7f6fea2379cc9e6441ade.png# 优化后的复合索引

DROP INDEX `idx_mid_status_cid` ON `article`;

CREATE INDEX `idx_mid_cid` ON `article` (`member_id`, `category_id`);

# 复合索引的所有字段全部用到

# 索引的作用:查询和排序

EXPLAIN SELECT `id`, `member_id` FROM `article` WHERE `member_id` = 2 AND `status` 

b1fa62d2041d616f2908dee627ed016c.png

LIKE 以通配符开头的模糊查询将不能使用索引,如 LIKE '%ello'。

尽可能使用覆盖索引(即查询列和索引列一致),避免使用 SELECT *。# intro 没有创建索引,未使用到覆盖索引

EXPLAIN SELECT `id`, `intro` FROM `article` WHERE `intro` LIKE '%a%';

# 创建索引

CREATE INDEX `idx_intro_status` ON `article` (`intro`, `status`);

# 索引失效

SELECT `intro` FROM `article` WHERE `intro` LIKE '%a';

# 查询列和索引列不一致,未使用到覆盖索引

EXPLAIN SELECT `category_id` FROM `article` WHERE `intro` LIKE '%a%';

EXPLAIN SELECT `category_id`, `intro`, `status` FROM `article` WHERE `intro` LIKE '%a%';

EXPLAIN SELECT * FROM `article` WHERE `intro` LIKE '%a%';

e0f1ff1eb223803929db6b819e61de16.png# 查询列和索引列一致,使用到了覆盖索引

EXPLAIN SELECT `id`, `intro` FROM `article` WHERE `intro` LIKE '%a%';

EXPLAIN SELECT `intro` FROM `article` WHERE `intro` LIKE '%a%';

EXPLAIN SELECT `intro`, `status` FROM `article` WHERE `intro` LIKE '%a%';

581874c8512cf9e15d7ee949f2fdb699.png# 由 key_len 可知使用到了复合索引所有字段

EXPLAIN SELECT * FROM `article` WHERE `intro` LIKE 'a%b%' AND `status` = 0;

136a2d21dd44fd8ba92bbbc0f4fa2813.png

不要在索引列进行任何操作,如计算、函数、类型转换、IS NULL、IS NOT NULL、OR、不等于判断,否则将导致索引失效转为全表扫描。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值