索引优化实战七

水深无声 2022-08-28 13:46 265阅读 0赞

一 like 的前后模糊匹配

like 以通配符开头(’%abc…’),mysql 索引失效会变成全表扫描的操作。

二 实战

  1. # % 作为 like 的前缀,会失效
  2. mysql> explain select * from staffs where name like '%July%';
  3. +----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
  4. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  5. +----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
  6. | 1 | SIMPLE | staffs | NULL | ALL | NULL | NULL | NULL | NULL | 3 | 33.33 | Using where |
  7. +----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
  8. 1 row in set, 1 warning (0.00 sec)
  9. # % 作为 like 的前缀,会失效
  10. mysql> explain select * from staffs where name like '%July';
  11. +----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
  12. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  13. +----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
  14. | 1 | SIMPLE | staffs | NULL | ALL | NULL | NULL | NULL | NULL | 3 | 33.33 | Using where |
  15. +----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
  16. 1 row in set, 1 warning (0.00 sec)
  17. # 索引生效:% like 加右边
  18. mysql> explain select * from staffs where name like 'July';
  19. +----+-------------+--------+------------+-------+-------------------------+-------------------------+---------+------+------+----------+-----------------------+
  20. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  21. +----+-------------+--------+------------+-------+-------------------------+-------------------------+---------+------+------+----------+-----------------------+
  22. | 1 | SIMPLE | staffs | NULL | range | index_staffs_nameAgePos | index_staffs_nameAgePos | 74 | NULL | 1 | 100.00 | Using index condition |
  23. +----+-------------+--------+------------+-------+-------------------------+-------------------------+---------+------+------+----------+-----------------------+
  24. 1 row in set, 1 warning (0.00 sec)

三 解决 like ‘%字符串%’时,索引不被使用的方法

1 表脚本

  1. CREATE TABLE `tbl_user`(
  2. `id` INT(11) NOT NULL AUTO_INCREMENT,
  3. `name` VARCHAR(20) DEFAULT NULL,
  4. `age`INT(11) DEFAULT NULL,
  5. `email` VARCHAR(20) DEFAULT NULL,
  6. PRIMARY KEY(`id`)
  7. )ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
  8. INSERT INTO tbl_user(`name`,`age`,`email`)VALUES('1aa1',21,'a@163.com');
  9. INSERT INTO tbl_user(`name`,`age`,`email`)VALUES('2bb2',23,'b@163.com');
  10. INSERT INTO tbl_user(`name`,`age`,`email`)VALUES('3cc3',24,'c@163.com');
  11. INSERT INTO tbl_user(`name`,`age`,`email`)VALUES('4dd4',26,'d@163.com');

2 操作

  1. # 建立索引前,全表扫描
  2. mysql> explain select name,age from tbl_user where name like '%aa%';
  3. +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
  4. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  5. +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
  6. | 1 | SIMPLE | tbl_user | NULL | ALL | NULL | NULL | NULL | NULL | 4 | 25.00 | Using where |
  7. +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
  8. 1 row in set, 1 warning (0.00 sec)
  9. # 建立索引前,全表扫描
  10. mysql> explain select id from tbl_user where name like '%aa%';
  11. +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
  12. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  13. +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
  14. | 1 | SIMPLE | tbl_user | NULL | ALL | NULL | NULL | NULL | NULL | 4 | 25.00 | Using where |
  15. +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
  16. 1 row in set, 1 warning (0.00 sec)
  17. # 建立索引前,全表扫描
  18. mysql> explain select name from tbl_user where name like '%aa%';
  19. +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
  20. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  21. +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
  22. | 1 | SIMPLE | tbl_user | NULL | ALL | NULL | NULL | NULL | NULL | 4 | 25.00 | Using where |
  23. +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
  24. 1 row in set, 1 warning (0.00 sec)
  25. # 建立索引前,全表扫描
  26. mysql> explain select age from tbl_user where name like '%aa%';
  27. +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
  28. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  29. +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
  30. | 1 | SIMPLE | tbl_user | NULL | ALL | NULL | NULL | NULL | NULL | 4 | 25.00 | Using where |
  31. +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
  32. 1 row in set, 1 warning (0.00 sec)
  33. # 建立索引前,全表扫描
  34. mysql> explain select name,age from tbl_user where name like '%aa%';
  35. +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
  36. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  37. +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
  38. | 1 | SIMPLE | tbl_user | NULL | ALL | NULL | NULL | NULL | NULL | 4 | 25.00 | Using where |
  39. +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
  40. 1 row in set, 1 warning (0.00 sec)
  41. # 建立索引
  42. mysql> create index idx_user_nameAge on tbl_user(Name,age);
  43. Query OK, 0 rows affected (0.05 sec)
  44. Records: 0 Duplicates: 0 Warnings: 0
  45. # 使用到覆盖索引,索引生效
  46. mysql> explain select name,age from tbl_user where name like '%aa%';
  47. +----+-------------+----------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
  48. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  49. +----+-------------+----------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
  50. | 1 | SIMPLE | tbl_user | NULL | index | NULL | idx_user_nameAge | 68 | NULL | 4 | 25.00 | Using where; Using index |
  51. +----+-------------+----------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
  52. 1 row in set, 1 warning (0.00 sec)
  53. # 使用覆盖索引,索引生效
  54. mysql> explain select id from tbl_user where name like '%aa%';
  55. +----+-------------+----------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
  56. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  57. +----+-------------+----------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
  58. | 1 | SIMPLE | tbl_user | NULL | index | NULL | idx_user_nameAge | 68 | NULL | 4 | 25.00 | Using where; Using index |
  59. +----+-------------+----------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
  60. 1 row in set, 1 warning (0.00 sec)
  61. # 使用覆盖索引,索引生效
  62. mysql> explain select name from tbl_user where name like '%aa%';
  63. +----+-------------+----------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
  64. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  65. +----+-------------+----------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
  66. | 1 | SIMPLE | tbl_user | NULL | index | NULL | idx_user_nameAge | 68 | NULL | 4 | 25.00 | Using where; Using index |
  67. +----+-------------+----------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
  68. 1 row in set, 1 warning (0.00 sec)
  69. # 使用覆盖索引,索引生效
  70. mysql> explain select age from tbl_user where name like '%aa%';
  71. +----+-------------+----------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
  72. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  73. +----+-------------+----------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
  74. | 1 | SIMPLE | tbl_user | NULL | index | NULL | idx_user_nameAge | 68 | NULL | 4 | 25.00 | Using where; Using index |
  75. +----+-------------+----------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
  76. 1 row in set, 1 warning (0.00 sec)
  77. # 使用覆盖索引,索引生效
  78. mysql> explain select id,name from tbl_user where name like '%aa%';
  79. +----+-------------+----------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
  80. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  81. +----+-------------+----------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
  82. | 1 | SIMPLE | tbl_user | NULL | index | NULL | idx_user_nameAge | 68 | NULL | 4 | 25.00 | Using where; Using index |
  83. +----+-------------+----------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
  84. 1 row in set, 1 warning (0.00 sec)
  85. # 使用覆盖索引,索引生效
  86. mysql> explain select id,name,age from tbl_user where name like '%aa%';
  87. +----+-------------+----------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
  88. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  89. +----+-------------+----------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
  90. | 1 | SIMPLE | tbl_user | NULL | index | NULL | idx_user_nameAge | 68 | NULL | 4 | 25.00 | Using where; Using index |
  91. +----+-------------+----------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
  92. 1 row in set, 1 warning (0.00 sec)
  93. # 使用覆盖索引,索引生效,主要是 email 惹的祸
  94. mysql> explain select name,age from tbl_user where name like '%aa%';
  95. +----+-------------+----------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
  96. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  97. +----+-------------+----------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
  98. | 1 | SIMPLE | tbl_user | NULL | index | NULL | idx_user_nameAge | 68 | NULL | 4 | 25.00 | Using where; Using index |
  99. +----+-------------+----------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
  100. 1 row in set, 1 warning (0.00 sec)
  101. # 没能用到覆盖索引,索引失效
  102. mysql> explain select * from tbl_user where name like '%aa%';
  103. +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
  104. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  105. +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
  106. | 1 | SIMPLE | tbl_user | NULL | ALL | NULL | NULL | NULL | NULL | 4 | 25.00 | Using where |
  107. +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
  108. 1 row in set, 1 warning (0.00 sec)
  109. # 没能用到覆盖索引,索引失效,主要是 email 惹的祸
  110. mysql> explain select id,name,age,email from tbl_user where name like '%aa%';
  111. +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
  112. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  113. +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
  114. | 1 | SIMPLE | tbl_user | NULL | ALL | NULL | NULL | NULL | NULL | 4 | 25.00 | Using where |
  115. +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
  116. 1 row in set, 1 warning (0.00 sec)

3 结论

使用覆盖索引可以解决问题。

发表评论

表情:
评论列表 (有 0 条评论,265人围观)

还没有评论,来说两句吧...

相关阅读

    相关 索引优化实战

     一  不要在索引列上做任何计算 不在索引列上做任何操作(计算、函数、(自动 or 手动)类型转换),会导致索引失效而转向全表扫描。 二 实战 等号左边