【问题标题】:Why isn't MySQL using any of these possible keys?为什么 MySQL 不使用这些可能的键中的任何一个?
【发布时间】:2011-08-08 19:55:07
【问题描述】:

我有以下疑问:

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

当我执行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

为什么key是NULL?

【问题讨论】:

  • 您应该粘贴整个 EXPLAIN 输出。从表面上看,表 t 没有限制因素,这意味着您的查询从表 t 中获取所有数据,因此无需使用任何索引。
  • 也许您的查询会返回 account_transaction 中的所有行,在这种情况下,键可能没有用处。

标签: mysql sql


【解决方案1】:

这可能是因为统计信息被破坏了,或者因为它知道你在两个表之间总是有 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 不使用索引是有原因的。它通过不使用索引使您的查询更快。不要通过强制索引来减慢它。无论如何,请始终为您的选择计时。
  • @Johan,但是there are cases 哪里是guesses are severely bad。除非你优化的是开发速度,否则最好自己做。
【解决方案2】:

group by 的索引(=隐式 order by

...
GROUP BY tc.id

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

这将使潜在索引transaction_code_id 进入视图。

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

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

【讨论】:

  • IIRC 是什么意思?
  • IIRC:如果我没记错的话
【解决方案3】:

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

SELECT * FROM tbl WHERE col = 12345; # No index
SELECT * FROM tbl WHERE col = '12345'; # Index

资料来源:今天刚刚解决了同样的问题,并在 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)

【讨论】:

  • 确实是这样...用 MySQL 的输出更新评论以进行验证。
  • 在 MySQL 中创建了一个关于此问题的错误。在这里登录以防其他参与此线程的人感兴趣。link
  • 今天发生在我们身上:mysql没有使用索引加入,因为table1是utf8而table2是latin1
  • Props to @benhsu ...今天遇到了同样的问题,您的评论触发了我的解决方案....谢谢!
  • 我遇到了与 Spikes 描述的相同的问题,但是在连接两列时,其中一列是 varchar,另一列是 int。
猜你喜欢
  • 2022-08-09
  • 1970-01-01
  • 2011-01-22
  • 1970-01-01
  • 2011-02-03
  • 2022-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多