创建索引

官方文档:

mysql> show create table test_index_1\G * 1. row * Table: test_index_1 Create Table: CREATE TABLE test_index_1 ( a int(11) DEFAULT NULL, b int(11) DEFAULT NULL, c int(11) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 1 row in set (0.00 sec)

mysql> insert into test_index_1 values -> (1,10,100),(2,20,200), -> (3,30,300),(4,40,400); Query OK, 4 rows affected (0.03 sec) Records: 4 Duplicates: 0 Warnings: 0

mysql> select * from test_index_1; +———+———+———+ | a | b | c | +———+———+———+ | 1 | 10 | 100 | | 2 | 20 | 200 | | 3 | 30 | 300 | | 4 | 40 | 400 | +———+———+———+ 4 rows in set (0.00 sec)

mysql> explain select from test_index_1 where a=3\G — 看执行计划,使用的是扫描整张表的方式 ** 1. row * id: 1 select_type: SIMPLE table: test_index_1 partitions: NULL type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 4 filtered: 25.00 Extra: Using where 1 row in set, 1 warning (0.00 sec)

— 给字段a 增加索引 mysql> alter table test_index_1 add index idx_a (a); — 给字段a添加索引。索引名为idx_a Query OK, 0 rows affected (0.15 sec) Records: 0 Duplicates: 0 Warnings: 0

mysql> explain select from test_index_1 where a=3\G — 看执行计划,使用的key为idx_a,走了索引 ** 1. row * id: 1 select_type: SIMPLE table: test_index_1 partitions: NULL type: ref possible_keys: idx_a key: idx_a key_len: 5 ref: const rows: 1 filtered: 100.00 Extra: NULL 1 row in set, 1 warning (0.00 sec)

— 使用create index mysql> explain select from test_index_1 where b=30\G — 同样b字段也没有索引 ** 1. row * id: 1 select_type: SIMPLE table: test_index_1 partitions: NULL type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 4 filtered: 25.00 Extra: Using where 1 row in set, 1 warning (0.00 sec)

— 给b字段增加索引 mysql> create index idx_b on test_index_1 (b); Query OK, 0 rows affected (0.14 sec) Records: 0 Duplicates: 0 Warnings: 0

mysql> explain select from test_index_1 where b=30\G — 查看执行计划,使用的key为idx_b,走了索引 ** 1. row * id: 1 select_type: SIMPLE table: test_index_1 partitions: NULL type: ref possible_keys: idx_b key: idx_b key_len: 5 ref: const rows: 1 filtered: 100.00 Extra: NULL 1 row in set, 1 warning (0.00 sec)

  1. <a name="46MHh"></a>
  2. ### 查看索引
  3. ```sql
  4. --
  5. -- 方式一
  6. --
  7. mysql> desc orders;
  8. +-----------------+-------------+------+-----+---------+-------+
  9. | Field | Type | Null | Key | Default | Extra |
  10. +-----------------+-------------+------+-----+---------+-------+
  11. | o_orderkey | int(11) | NO | PRI | NULL | | -- 索引
  12. | o_custkey | int(11) | YES | MUL | NULL | | -- 索引
  13. | o_orderstatus | char(1) | YES | | NULL | |
  14. | o_totalprice | double | YES | | NULL | |
  15. | o_orderDATE | date | YES | MUL | NULL | | -- 索引
  16. | o_orderpriority | char(15) | YES | | NULL | |
  17. | o_clerk | char(15) | YES | | NULL | |
  18. | o_shippriority | int(11) | YES | | NULL | |
  19. | o_comment | varchar(79) | YES | | NULL | |
  20. +-----------------+-------------+------+-----+---------+-------+
  21. 9 rows in set (0.00 sec)
  22. --
  23. -- 方式二
  24. --
  25. mysql> show create table orders\G
  26. *************************** 1. row ***************************
  27. Table: orders
  28. Create Table: CREATE TABLE `orders` (
  29. `o_orderkey` int(11) NOT NULL,
  30. `o_custkey` int(11) DEFAULT NULL,
  31. `o_orderstatus` char(1) DEFAULT NULL,
  32. `o_totalprice` double DEFAULT NULL,
  33. `o_orderDATE` date DEFAULT NULL,
  34. `o_orderpriority` char(15) DEFAULT NULL,
  35. `o_clerk` char(15) DEFAULT NULL,
  36. `o_shippriority` int(11) DEFAULT NULL,
  37. `o_comment` varchar(79) DEFAULT NULL,
  38. PRIMARY KEY (`o_orderkey`), -- 索引
  39. KEY `i_o_orderdate` (`o_orderDATE`), -- 索引
  40. KEY `i_o_custkey` (`o_custkey`), -- 索引
  41. CONSTRAINT `orders_ibfk_1` FOREIGN KEY (`o_custkey`) REFERENCES `customer` (`c_custkey`)
  42. ) ENGINE=InnoDB DEFAULT CHARSET=latin1
  43. 1 row in set (0.00 sec)
  44. --
  45. -- 方式三
  46. --
  47. mysql> show index from orders\G
  48. *************************** 1. row ***************************
  49. Table: orders
  50. Non_unique: 0 -- 表示唯一的
  51. Key_name: PRIMARY -- key的name是primary
  52. Seq_in_index: 1
  53. Column_name: o_orderkey
  54. Collation: A
  55. Cardinality: 1306748 -- 基数,这个列上不同值的记录数
  56. Sub_part: NULL
  57. Packed: NULL
  58. Null:
  59. Index_type: BTREE -- 索引类型是BTree
  60. Comment:
  61. Index_comment:
  62. *************************** 2. row ***************************
  63. Table: orders
  64. Non_unique: 1 -- Non_unique为True,表示不唯一
  65. Key_name: i_o_orderdate
  66. Seq_in_index: 1
  67. Column_name: o_orderDATE
  68. Collation: A
  69. Cardinality: 2405
  70. Sub_part: NULL
  71. Packed: NULL
  72. Null: YES
  73. Index_type: BTREE
  74. Comment:
  75. Index_comment:
  76. *************************** 3. row ***************************
  77. Table: orders
  78. Non_unique: 1
  79. Key_name: i_o_custkey
  80. Seq_in_index: 1
  81. Column_name: o_custkey
  82. Collation: A
  83. Cardinality: 95217
  84. Sub_part: NULL
  85. Packed: NULL
  86. Null: YES
  87. Index_type: BTREE
  88. Comment:
  89. Index_comment:
  90. 3 rows in set (0.00 sec)
  91. mysql> select count(*) from orders;
  92. +----------+
  93. | count(*) |
  94. +----------+
  95. | 1500000 | -- orders中有150W条记录,和Cardinality 是不一致的
  96. +----------+
  97. 1 row in set (0.25 sec)

Cardinality(基数)

Cardinality 表示该索引列上有多少不同的记录,这个是一个预估的值,是采样得到的(由 InnoDB 触发,采样20个页,进行预估),该值越大越好,即当 Cardinality / RowNumber 越接近1越好,表示该列是高选择性的。

  • 高选择性:身份证 、手机号码、姓名、订单号等。
  • 低选择性:性别、年龄等。

即该列是否适合创建索引,就看该字段是否具有高选择性。

  1. mysql> show create table lineitem\G
  2. *************************** 1. row ***************************
  3. Table: lineitem
  4. Create Table: CREATE TABLE `lineitem` (
  5. `l_orderkey` int(11) NOT NULL,
  6. `l_partkey` int(11) DEFAULT NULL,
  7. `l_suppkey` int(11) DEFAULT NULL,
  8. `l_linenumber` int(11) NOT NULL,
  9. `l_quantity` double DEFAULT NULL,
  10. `l_extendedprice` double DEFAULT NULL,
  11. `l_discount` double DEFAULT NULL,
  12. `l_tax` double DEFAULT NULL,
  13. `l_returnflag` char(1) DEFAULT NULL,
  14. `l_linestatus` char(1) DEFAULT NULL,
  15. `l_shipDATE` date DEFAULT NULL,
  16. `l_commitDATE` date DEFAULT NULL,
  17. `l_receiptDATE` date DEFAULT NULL,
  18. `l_shipinstruct` char(25) DEFAULT NULL,
  19. `l_shipmode` char(10) DEFAULT NULL,
  20. `l_comment` varchar(44) DEFAULT NULL,
  21. PRIMARY KEY (`l_orderkey`,`l_linenumber`), -- 两个列作为primary
  22. KEY `i_l_shipdate` (`l_shipDATE`),
  23. KEY `i_l_suppkey_partkey` (`l_partkey`,`l_suppkey`),
  24. KEY `i_l_partkey` (`l_partkey`),
  25. KEY `i_l_suppkey` (`l_suppkey`),
  26. KEY `i_l_receiptdate` (`l_receiptDATE`),
  27. KEY `i_l_orderkey` (`l_orderkey`),
  28. KEY `i_l_orderkey_quantity` (`l_orderkey`,`l_quantity`),
  29. KEY `i_l_commitdate` (`l_commitDATE`),
  30. CONSTRAINT `lineitem_ibfk_1` FOREIGN KEY (`l_orderkey`) REFERENCES `orders` (`o_orderkey`),
  31. CONSTRAINT `lineitem_ibfk_2` FOREIGN KEY (`l_partkey`, `l_suppkey`) REFERENCES `partsupp` (`ps_partkey`, `ps_suppkey`)
  32. ) ENGINE=InnoDB DEFAULT CHARSET=latin1
  33. 1 row in set (0.00 sec)
  34. mysql> show index from lineitem\G -- 省略其他输出,只看PRIMARY
  35. *************************** 1. row ***************************
  36. Table: lineitem
  37. Non_unique: 0
  38. Key_name: PRIMARY
  39. Seq_in_index: 1 -- 索引中的顺序,该列的顺序为1
  40. Column_name: l_orderkey
  41. Collation: A
  42. Cardinality: 1416486 -- 140W
  43. Sub_part: NULL
  44. Packed: NULL
  45. Null:
  46. Index_type: BTREE
  47. Comment:
  48. Index_comment:
  49. *************************** 2. row ***************************
  50. Table: lineitem
  51. Non_unique: 0
  52. Key_name: PRIMARY
  53. Seq_in_index: 2 -- 索引中的顺序,该列的顺序为2
  54. Column_name: l_linenumber
  55. Collation: A
  56. Cardinality: 5882116 -- 580W
  57. Sub_part: NULL
  58. Packed: NULL
  59. Null:
  60. Index_type: BTREE
  61. Comment:
  62. Index_comment:

对应当前例子:

  • 第一个索引(Seq_in_index = 1)的 Cardinality 的值表示当前列(l_orderkey)的不重复的值。
  • 第二个索引(Seq_in_index = 2)的 Cardinality 的值表示前两列(l_orderkey)和(l_linenumber)不重复的值。

    ```sql

    — SQL-1

    mysql> select * from lineitem limit 10;
    +——————+—————-+—————-+———————+——————+————————-+——————+———-+———————+———————+——————+———————+———————-+—————————-+——————+————————————————————+ | l_orderkey | l_partkey | l_suppkey | l_linenumber | l_quantity | l_extendedprice | l_discount | l_tax | l_returnflag | l_linestatus | l_shipDATE | l_commitDATE | l_receiptDATE | l_shipinstruct | l_shipmode | l_comment | +——————+—————-+—————-+———————+——————+————————-+——————+———-+———————+———————+——————+———————+———————-+—————————-+——————+————————————————————+ | 1 | 155190 | 7706 | 1 | 17 | 21168.23 | 0.04 | 0.02 | N | O | 1996-03-13 | 1996-02-12 | 1996-03-22 | DELIVER IN PERSON | TRUCK | blithely regular ideas caj | | 1 | 67310 | 7311 | 2 | 36 | 45983.16 | 0.09 | 0.06 | N | O | 1996-04-12 | 1996-02-28 | 1996-04-20 | TAKE BACK RETURN | MAIL | slyly bold pinto beans detect s | | 1 | 63700 | 3701 | 3 | 8 | 13309.6 | 0.1 | 0.02 | N | O | 1996-01-29 | 1996-03-05 | 1996-01-31 | TAKE BACK RETURN | REG AIR | deposits wake furiously dogged, | | 1 | 2132 | 4633 | 4 | 28 | 28955.64 | 0.09 | 0.06 | N | O | 1996-04-21 | 1996-03-30 | 1996-05-16 | NONE | AIR | even ideas haggle. even, bold reque | | 1 | 24027 | 1534 | 5 | 24 | 22824.48 | 0.1 | 0.04 | N | O | 1996-03-30 | 1996-03-14 | 1996-04-01 | NONE | FOB | carefully final gr | | 1 | 15635 | 638 | 6 | 32 | 49620.16 | 0.07 | 0.02 | N | O | 1996-01-30 | 1996-02-07 | 1996-02-03 | DELIVER IN PERSON | MAIL | furiously regular accounts haggle bl | | 2 | 106170 | 1191 | 1 | 38 | 44694.46 | 0 | 0.05 | N | O | 1997-01-28 | 1997-01-14 | 1997-02-02 | TAKE BACK RETURN | RAIL | carefully ironic platelets against t | | 3 | 4297 | 1798 | 1 | 45 | 54058.05 | 0.06 | 0 | R | F | 1994-02-02 | 1994-01-04 | 1994-02-23 | NONE | AIR | blithely s | | 3 | 19036 | 6540 | 2 | 49 | 46796.47 | 0.1 | 0 | R | F | 1993-11-09 | 1993-12-20 | 1993-11-24 | TAKE BACK RETURN | RAIL | final, regular pinto | | 3 | 128449 | 3474 | 3 | 27 | 39890.88 | 0.06 | 0.07 | A | F | 1994-01-16 | 1993-11-22 | 1994-01-23 | DELIVER IN PERSON | SHIP | carefully silent pinto beans boost fur | +——————+—————-+—————-+———————+——————+————————-+——————+———-+———————+———————+——————+———————+———————-+—————————-+——————+————————————————————+ 10 rows in set (0.00 sec)

— SQL-2

mysql> select l_orderkey, l_linenumber from lineitem limit 10; +——————+———————+ | l_orderkey | l_linenumber | +——————+———————+ | 721220 | 2 | | 842980 | 4 | | 904677 | 1 | | 990147 | 1 | | 1054181 | 1 | | 1111877 | 3 | | 1332613 | 1 | | 1552449 | 2 | | 2167527 | 3 | | 2184032 | 5 | +——————+———————+ 10 rows in set (0.00 sec)

—- SQL-1 和 SQL-2 其实都是在没有排序的情况下,取出前10条数据。但是结果不一样

— SQL-3

mysql> select l_orderkey, l_linenumber from lineitem order by l_orderkey limit 10; — 和上面的sql相比,多了一个order by的操作 +——————+———————+ | l_orderkey | l_linenumber | +——————+———————+ | 1 | 1 | ——- | 1 | 2 | — 看orderkey为1,对应的linenumber有6条 | 1 | 3 | — 这就是orderkey的Cardinality仅为140W | 1 | 4 | — 而(orderkey + linenumber)就有580W | 1 | 5 | | 1 | 6 | ——- | 2 | 1 | | 3 | 1 | | 3 | 2 | | 3 | 3 | +——————+———————+ 10 rows in set (0.01 sec)

—- SQL-3 和 SQL-2 不同的原因是 他们走了不同的索引 mysql> explain select l_orderkey, l_linenumber from lineitem limit 10\G * 1. row * id: 1 select_type: SIMPLE table: lineitem partitions: NULL type: index possible_keys: NULL key: i_l_shipdate — 使用了shipdate进行了索引 key_len: 4 ref: NULL rows: 5882306 filtered: 100.00 Extra: Using index 1 row in set, 1 warning (0.00 sec)

mysql> explain select l_orderkey, l_linenumber from lineitem order by l_orderkey limit 10\G * 1. row * id: 1 select_type: SIMPLE table: lineitem partitions: NULL type: index possible_keys: NULL key: i_l_orderkey — 使用了orderkey进行了查询 key_len: 4 ref: NULL rows: 10 filtered: 100.00 Extra: Using index 1 row in set, 1 warning (0.00 sec)

mysql> explain select from lineitem limit 10\G ** 1. row * id: 1 select_type: SIMPLE table: lineitem partitions: NULL type: ALL — SQL-1进行了全表扫描 possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 5882306 filtered: 100.00 Extra: NULL 1 row in set, 1 warning (0.00 sec)

— 所以,不使用order by取出的结果,可以理解为不是根据主键排序的结果。

  1. MySQL5.5 之前,执行 show create table 操作会触发采样,而 5.5 之后将该参数(`innodb_stats_on_metadata = off` off 后,需要主动执行 analyze table 才会去采样,采样不会锁表或者锁记录。
  2. <a name="K9PoR"></a>
  3. ### 复合索引
  4. ```sql
  5. mysql> show create table lineitem\G
  6. *************************** 1. row ***************************
  7. Table: lineitem
  8. Create Table: CREATE TABLE `lineitem` (
  9. `l_orderkey` int(11) NOT NULL,
  10. `l_partkey` int(11) DEFAULT NULL,
  11. `l_suppkey` int(11) DEFAULT NULL,
  12. `l_linenumber` int(11) NOT NULL,
  13. `l_quantity` double DEFAULT NULL,
  14. `l_extendedprice` double DEFAULT NULL,
  15. `l_discount` double DEFAULT NULL,
  16. `l_tax` double DEFAULT NULL,
  17. `l_returnflag` char(1) DEFAULT NULL,
  18. `l_linestatus` char(1) DEFAULT NULL,
  19. `l_shipDATE` date DEFAULT NULL,
  20. `l_commitDATE` date DEFAULT NULL,
  21. `l_receiptDATE` date DEFAULT NULL,
  22. `l_shipinstruct` char(25) DEFAULT NULL,
  23. `l_shipmode` char(10) DEFAULT NULL,
  24. `l_comment` varchar(44) DEFAULT NULL,
  25. PRIMARY KEY (`l_orderkey`,`l_linenumber`), -- 两个列作为primary,这个就是复合索引
  26. KEY `i_l_shipdate` (`l_shipDATE`),
  27. KEY `i_l_suppkey_partkey` (`l_partkey`,`l_suppkey`),
  28. KEY `i_l_partkey` (`l_partkey`),
  29. KEY `i_l_suppkey` (`l_suppkey`),
  30. KEY `i_l_receiptdate` (`l_receiptDATE`),
  31. KEY `i_l_orderkey` (`l_orderkey`),
  32. KEY `i_l_orderkey_quantity` (`l_orderkey`,`l_quantity`),
  33. KEY `i_l_commitdate` (`l_commitDATE`),
  34. CONSTRAINT `lineitem_ibfk_1` FOREIGN KEY (`l_orderkey`) REFERENCES `orders` (`o_orderkey`),
  35. CONSTRAINT `lineitem_ibfk_2` FOREIGN KEY (`l_partkey`, `l_suppkey`) REFERENCES `partsupp` (`ps_partkey`, `ps_suppkey`)
  36. ) ENGINE=InnoDB DEFAULT CHARSET=latin1
  37. 1 row in set (0.00 sec)
  38. --
  39. -- 复合索引举例
  40. --
  41. mysql> create table test_index_2(a int, b int , c int);
  42. Query OK, 0 rows affected (0.15 sec)
  43. mysql> alter table test_index_2 add index idx_mul_ab (a, b);
  44. Query OK, 0 rows affected (0.11 sec)
  45. Records: 0 Duplicates: 0 Warnings: 0
  46. mysql> insert into test_index_2 values
  47. -> (1,1,10),
  48. -> (1,2,9),
  49. -> (2,1,8),
  50. -> (2,4,15),
  51. -> (3,1,6),
  52. -> (3,2,17);
  53. Query OK, 6 rows affected (0.04 sec)
  54. Records: 6 Duplicates: 0 Warnings: 0
  55. mysql> select * from test_index_2 where a = 1;
  56. +------+------+------+
  57. | a | b | c |
  58. +------+------+------+
  59. | 1 | 1 | 10 |
  60. | 1 | 2 | 9 |
  61. +------+------+------+
  62. 2 rows in set (0.00 sec)
  63. mysql> explain select * from test_index_2 where a = 1\G
  64. *************************** 1. row ***************************
  65. id: 1
  66. select_type: SIMPLE
  67. table: test_index_2
  68. partitions: NULL
  69. type: ref
  70. possible_keys: idx_mul_ab
  71. key: idx_mul_ab -- 走了索引
  72. key_len: 5
  73. ref: const
  74. rows: 2
  75. filtered: 100.00
  76. Extra: NULL
  77. 1 row in set, 1 warning (0.00 sec)
  78. mysql> select * from test_index_2 where a = 1 and b = 2;
  79. +------+------+------+
  80. | a | b | c |
  81. +------+------+------+
  82. | 1 | 2 | 9 |
  83. +------+------+------+
  84. 1 row in set (0.00 sec)
  85. mysql> explain select * from test_index_2 where a = 1 and b = 2\G
  86. *************************** 1. row ***************************
  87. id: 1
  88. select_type: SIMPLE
  89. table: test_index_2
  90. partitions: NULL
  91. type: ref -- 此时也是走了索引
  92. possible_keys: idx_mul_ab
  93. key: idx_mul_ab
  94. key_len: 10
  95. ref: const,const
  96. rows: 1
  97. filtered: 100.00
  98. Extra: NULL
  99. 1 row in set, 1 warning (0.00 sec)
  100. mysql> explain select * from test_index_2 where b = 2\G -- 只查询b
  101. *************************** 1. row ***************************
  102. id: 1
  103. select_type: SIMPLE
  104. table: test_index_2
  105. partitions: NULL
  106. type: ALL -- 没有使用索引
  107. possible_keys: NULL
  108. key: NULL
  109. key_len: NULL
  110. ref: NULL
  111. rows: 6
  112. filtered: 16.67
  113. Extra: Using where
  114. 1 row in set, 1 warning (0.00 sec)
  115. mysql> explain select * from test_index_2 where a=1 or b = 2\G -- 使用or,要求结果集是并集
  116. *************************** 1. row ***************************
  117. id: 1
  118. select_type: SIMPLE
  119. table: test_index_2
  120. partitions: NULL
  121. type: ALL -- 没有使用索引,因为b没有索引,所以b是走全表扫描的,既然走扫描,a的值也可以一起过滤
  122. -- 就没有必要在去查一次 a 的索引了
  123. possible_keys: idx_mul_ab
  124. key: NULL
  125. key_len: NULL
  126. ref: NULL
  127. rows: 6
  128. filtered: 30.56
  129. Extra: Using where
  130. 1 row in set, 1 warning (0.00 sec)
  131. --
  132. -- 特别的例子
  133. --
  134. ---- 还是只使用b列去做范围查询,发现是走索引了
  135. ---- 注意查询的是 count(*)
  136. mysql> explain select count(*) from test_index_2 where b >1 and b < 3\G
  137. *************************** 1. row ***************************
  138. id: 1
  139. select_type: SIMPLE
  140. table: test_index_2
  141. partitions: NULL
  142. type: index -- 走了索引
  143. possible_keys: NULL
  144. key: idx_mul_ab
  145. key_len: 10
  146. ref: NULL
  147. rows: 6
  148. filtered: 16.67
  149. Extra: Using where; Using index -- 覆盖索引
  150. 1 row in set, 1 warning (0.00 sec)
  151. -- 因为要求的是count(*), 要求所有的记录的和,
  152. -- 那索引a是包含了全部的记录的,即扫描(a,b)的索引也是可以得到count(*)的
  153. mysql> explain select * from test_index_2 where b >1 and b < 3\G
  154. *************************** 1. row ***************************
  155. id: 1
  156. select_type: SIMPLE
  157. table: test_index_2
  158. partitions: NULL
  159. type: ALL -- 查询 * 就没法使用(a,b)索引了,需要全表扫描b的值。
  160. possible_keys: NULL
  161. key: NULL
  162. key_len: NULL
  163. ref: NULL
  164. rows: 6
  165. filtered: 16.67
  166. Extra: Using where
  167. 1 row in set, 1 warning (0.00 sec)
  168. mysql> explain select * from test_index_2 where a = 1 and c = 10\G
  169. *************************** 1. row ***************************
  170. id: 1
  171. select_type: SIMPLE
  172. table: test_index_2
  173. partitions: NULL
  174. type: ref -- 也是走索引的,先用走a索引得到结果集,再用c=10去过滤
  175. possible_keys: idx_mul_ab
  176. key: idx_mul_ab
  177. key_len: 5
  178. ref: const
  179. rows: 2
  180. filtered: 16.67
  181. Extra: Using where
  182. 1 row in set, 1 warning (0.00 sec)
  183. mysql> explain select * from test_index_2 where b = 2 and c = 10\G
  184. *************************** 1. row ***************************
  185. id: 1
  186. select_type: SIMPLE
  187. table: test_index_2
  188. partitions: NULL
  189. type: ALL -- 而b和c是不行的,(b,c)不是有序的
  190. possible_keys: NULL
  191. key: NULL
  192. key_len: NULL
  193. ref: NULL
  194. rows: 6
  195. filtered: 16.67
  196. Extra: Using where
  197. 1 row in set, 1 warning (0.00 sec)

FORCE INDEX & IGNORE INDEX

MySQL 可以使用 FORCE INDEX 和 IGNORE INDEX 命令来强制或者禁止使用某个索引。

  1. -- 没使用 force index ignore index 命令,默认使用 primary 索引
  2. mysql> explain select * from dept_emp where emp_no='10003';
  3. +----+-------------+----------+------------+------+----------------+---------+---------+-------+------+----------+-------+
  4. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  5. +----+-------------+----------+------------+------+----------------+---------+---------+-------+------+----------+-------+
  6. | 1 | SIMPLE | dept_emp | NULL | ref | PRIMARY,emp_no | PRIMARY | 4 | const | 1 | 100.00 | NULL |
  7. +----+-------------+----------+------------+------+----------------+---------+---------+-------+------+----------+-------+
  8. 1 row in set, 1 warning (0.00 sec)
  9. -- 强制使用 emp_no 索引
  10. mysql> explain select * from dept_emp force index(emp_no) where emp_no='10003';
  11. +----+-------------+----------+------------+------+---------------+--------+---------+-------+------+----------+-------+
  12. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  13. +----+-------------+----------+------------+------+---------------+--------+---------+-------+------+----------+-------+
  14. | 1 | SIMPLE | dept_emp | NULL | ref | emp_no | emp_no | 4 | const | 1 | 100.00 | NULL |
  15. +----+-------------+----------+------------+------+---------------+--------+---------+-------+------+----------+-------+
  16. 1 row in set, 1 warning (0.00 sec)
  17. -- 禁止使用 primary 索引
  18. mysql> explain select * from dept_emp ignore index(primary) where emp_no='10003';
  19. +----+-------------+----------+------------+------+---------------+--------+---------+-------+------+----------+-------+
  20. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  21. +----+-------------+----------+------------+------+---------------+--------+---------+-------+------+----------+-------+
  22. | 1 | SIMPLE | dept_emp | NULL | ref | emp_no | emp_no | 4 | const | 1 | 100.00 | NULL |
  23. +----+-------------+----------+------------+------+---------------+--------+---------+-------+------+----------+-------+
  24. 1 row in set, 1 warning (0.00 sec)

官方文档:https://dev.mysql.com/doc/refman/8.0/en/index-hints.html

MySQL 的官方文档指出这两个命令以后会被弃用。
image.png

作者:殷建卫 链接:https://www.yuque.com/yinjianwei/vyrvkf/yozvqv 来源:殷建卫 - 架构笔记 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。