MySQL索引在where子句和order by子句之间

时间:2013-06-12 22:43:27

标签: mysql performance query-optimization

我的表结构如下所示:

CREATE TABLE test (
    id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,

    field_1 VARCHAR(60) NOT NULL,
    field_2 INT(10) UNSIGNED NULL,
    field_3 INT(10) UNSIGNED NULL,
    field_4 INT(10) UNSIGNED NULL,
    field_5 CHAR(2) NULL,
    field_6 INT(10) UNSIGNED NOT NULL,

    rank TINYINT(2) NOT NULL DEFAULT '0',   
    status TINYINT(3) NOT NULL DEFAULT '0',

    PRIMARY KEY (id),
    INDEX (status)

) DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE = MyISAM;

在上表中,字段rankstatus的整数值分别介于0-9和0-4之间。

目前该表填充了大约950K数据,我正在尽可能地优化我的查询。

基本上我需要在字段rank上选择带有降序的where子句的字段。

例如,下面是几个sql查询:

SELECT field_1, field_2, field_3 FROM test WHERE field_1 = 'data1' && status IN ('0', '1', '2') ORDER BY rank DESC LIMIT 0, 20;
SELECT field_1, field_2, field_3 FROM test WHERE field_2 = '5' && status IN ('1', '2') ORDER BY rank DESC LIMIT 0, 20;
SELECT field_1, field_2, field_3 FROM test WHERE field_5 = 'US' && status IN ('0', '2') ORDER BY rank DESC LIMIT 0, 20;

在上面的查询ORDER BY rank DESC非常重要。所以我很想知道是否应该在单列或多列上添加索引。

任何人都可以向我推荐最佳解决方案。

1 个答案:

答案 0 :(得分:1)

您的关键问题是,您的status列超过950k行,最多有4个不同的值。在BTREE指数上,这将是一个真正的痛苦处理。

用于上述3个查询的一些更有效的索引是可能以下

INDEX forQuery1 ( field_1 , status , rank ) USING BTREE,
INDEX forQuery2 ( field_2 , status , rank ) USING BTREE,
INDEX forQuery3 ( field_5 , status , rank ) USING BTREE,

您会发现第二个查询尤其应该会受益,但是您仍然会遇到数据方差对于数据集大小非常低的问题,并且很可能MySQL会回退到表扫描你的EXPLAIN可能会显示LIMIT以减轻其影响。提到的索引应该适合于确定要返回的行。

有关MySQL如何使用索引的更多信息,请查看13.1.13. CREATE INDEX Syntax,特别是 B-Tree索引特征部分以及以下摘录

  

如果表有多列索引,则表示最左边的前缀   优化器可以使用index来查找行。例如,如果你   在(col1,col2,col3)上有一个三列索引,你已编入索引   搜索(col1),(col1,col2)和(col1,col2,col3)的功能。

     

如果列不形成最左边的前缀,则MySQL无法使用索引   的索引。假设您有SELECT语句:

  

有时MySQL不使用索引,即使有索引也是如此。一   发生这种情况的情况是优化程序估计的时间   使用索引需要MySQL访问非常大的   表中行的百分比。 (在这种情况下,表扫描是   可能会更快,因为它需要较少的搜索。)但是,如果   这样的查询使用LIMIT来检索MySQL使用的一些行   无论如何,索引,因为它可以更快地找到几行   返回结果。

作为补充说明,您不需要引用数值数据类型,因此field_2 = 5 && status IN ( 1 , 2 )是有效的(事实上,由于引用整数数据类型而不是将它们指定为,因此我在过去遇到了一些奇怪的问题数字)