错误的mysql索引选择

时间:2013-01-16 21:34:32

标签: mysql

我有一个大表(250M行),其中包含一个group_id列,可以将表大致分成组(group_id)。它有以下索引:

mysql> show indexes from table\G;
*************************** 13. row ***************************
       Table: table
  Non_unique: 1
    Key_name: myindex
Seq_in_index: 1
 Column_name: group_id
   Collation: A
 Cardinality: 181819
    Sub_part: NULL
      Packed: NULL
        Null: YES
  Index_type: BTREE
     Comment: 
*************************** 14. row ***************************
       Table: table
  Non_unique: 1
    Key_name: myindex
Seq_in_index: 2
 Column_name: id
   Collation: A
 Cardinality: 213456239
    Sub_part: NULL
      Packed: NULL
        Null: 
  Index_type: BTREE
     Comment: 

我想执行以下查询:

mysql> explain select * from `table` WHERE (`table`.`type_id` IN (11, 17, 12, 19) AND `table`.`group_id` = 310248) ORDER BY `table`.`id` ASC LIMIT 201\G

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: table
         type: index
possible_keys: [SOME INDEX NAMES]
          key: PRIMARY
      key_len: 4
          ref: NULL
         rows: 257386914
        Extra: Using where
1 row in set (0.00 sec)

我理解它需要扫描一些行,因为WHERE ... IN()的索引存在问题。然而,令我惊讶的是,它选择使用主键索引扫描几乎尽可能多的行。

以下似乎毫不含糊(显然)优越:

mysql> explain select * from `table` USE INDEX (myindex) WHERE (`table`.`type_id` IN (11, 17, 12, 19) AND `table`.`group_id` = 310248) ORDER BY `table`.`id` ASC LIMIT 201\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: table
         type: ref
possible_keys: myindex
          key: myindex
      key_len: 5
          ref: const
         rows: 1883760
        Extra: Using where
1 row in set (0.00 sec)

对LIMIT(2000)使用较大的值,使用不同的group_id值,删除ORDER BY并删除type_id过滤器都会导致它使用索引。我已经运行了ANALYZE TABLE。

值得注意的是行数估计很高:

mysql> select count(*) from table where group_id=310248 and type_id in (11, 17, 12, 19) ;
+----------+
| count(*) |
+----------+
|   583868 |
+----------+
1 row in set (0.61 sec)

mysql版本:

在x86_64上的debian-linux-gnu的Ver 5.1.57-rel12.8-log((Percona Server(GPL),12.8,Revision 233))

为什么mysql会选择一个它认为会涉及扫描257386914行而不是1883760行的计划?我知道它可能会重视顺序读取,但为什么它会选择2000行的索引,而不是200行?为什么要按不同的组ID过滤?

已编辑:我还尝试创建索引(group_id,id,type_id),以便只使用索引扫描完成所有排序,但我无法选择该索引。

1 个答案:

答案 0 :(得分:1)

你有问题吗?

请注意,因为必须检查type_id列上的谓词,并且因为您的查询至少返回了一个不在索引中的列,所以MySQL必须访问该表的数据页,为了访问这些列的值。

因此,MySQL可能偏爱群集密钥,因为那是数据页面的位置;群集密钥还允许MySQL避免排序操作(“使用filesort”)。 (我们注意到使用索引的执行计划也避免了排序操作。)

如果您希望MySQL支持您的索引,您可以考虑在该索引中包含type_id作为第三列,如果完全是选择性的话。

或者,您可以考虑将查询修改为“ORDER BY group_id,id”以影响优化程序。

您是否使用提示和没有提示来衡量查询的性能?

相关问题