为什么MySQL不使用这些可能的密钥?

Jas*_*ett 23 mysql sql

我有以下查询:

SELECT t.id
FROM account_transaction t
JOIN transaction_code tc ON t.transaction_code_id = tc.id
JOIN account a ON t.account_number = a.account_number
GROUP BY tc.id
Run Code Online (Sandbox Code Playgroud)

当我做EXPLAIN第一行时,除其他外,显示:

table: t
type: ALL
possible_keys: account_id,transaction_code_id,account_transaction_transaction_code_id,account_transaction_account_number
key: NULL
rows: 465663
Run Code Online (Sandbox Code Playgroud)

为什么键为NULL?

Spi*_*kes 53

您可能遇到的另一个问题是数据类型不匹配.例如,如果您的列是字符串数据类型(CHAR,例如),并且您的查询未引用数字,则MySQL将不使用该索引.

SELECT * FROM tbl WHERE col = 12345; # No index
SELECT * FROM tbl WHERE col = '12345'; # Index
Run Code Online (Sandbox Code Playgroud)

资料来源:今天刚刚解决了同样的问题,并在MySQL 5.1上学到了很多东西.:)

编辑:验证此信息的其他信息:

mysql> desc das_table \G
*************************** 1. row ***************************
  Field: das_column
   Type: varchar(32)
   Null: NO
    Key: PRI
Default: 
  Extra: 
*************************** 2. row ***************************
[SNIP!]

mysql> explain select * from das_table where das_column = 189017 \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: das_column
         type: ALL
possible_keys: PRIMARY
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 874282
        Extra: Using where
1 row in set (0.00 sec)

mysql> explain select * from das_table where das_column = '189017' \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: das_column
         type: const
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 34
          ref: const
         rows: 1
        Extra: 
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)

  • 这发生在我们今天:mysql没有使用索引加入因为table1是utf8而table2是latin1 (4认同)

jis*_*shi 17

这可能是因为统计数据被破坏,或者因为它知道您在两个表之间始终具有1:1的比率.

您可以强制在查询中使用索引,并查看是否会加快速度.如果是,请尝试运行ANALYZE TABLE以确保统计信息是最新的.

通过指定USE INDEX(index_list),您可以告诉MySQL仅使用其中一个命名索引来查找表中的行.替代语法IGNORE INDEX(index_list)可用于告诉MySQL不使用某些特定索引或索引.如果EXPLAIN显示MySQL正在使用可能索引列表中的错误索引,则这些提示很有用.

您还可以使用FORCE INDEX,其作用类似于USE INDEX(index_list),但另外还假设表扫描非常昂贵.换句话说,只有在无法使用某个给定索引查找表中的行时才使用表扫描.

每个提示都需要索引的名称,而不是列的名称.PRIMARY KEY的名称是PRIMARY.要查看表的索引名称,请使用SHOW INDEX.

来自http://dev.mysql.com/doc/refman/5.1/en/index-hints.html

  • 不要像这样的**简单**查询使用强制索引.MySQL没有使用索引是有原因的.它通过不使用索引使您的查询**更快**.不要通过强制索引来减慢速度.无论如何总是选择你的时间. (4认同)
  • @Johan,但是[在某些情况下](http://stackoverflow.com/a/5504594/632951)中,[猜测非常糟糕](http://code.openark.org/blog/mysql/7-ways说服mysql使用正确的索引)。除非您要优化的是开发速度,否则最好自己动手做。 (2认同)

Joh*_*ica 8

指数group by(=隐含order by)

...
GROUP BY tc.id
Run Code Online (Sandbox Code Playgroud)

group by对tc.id进行了隐式排序.
tc.id未列为可能的密钥.
但是t.transaction_id .

将代码更改为

SELECT t.id
FROM account_transaction t
JOIN transaction_code tc ON t.transaction_code_id = tc.id
JOIN account a ON t.account_number = a.account_number
GROUP BY t.transaction_code_id
Run Code Online (Sandbox Code Playgroud)

这将使潜在的指数transaction_code_id进入视野.

连接的索引
如果连接(几乎)完全连接三个表,则不需要使用索引,因此MySQL不需要.

不使用索引的其他原因
如果正在考虑的大部分行(40%IIRC)填充相同的值.MySQL不使用索引.(因为没有使用索引更快)

  • IIRC:如果我没记错的话 (2认同)