2

我的表结构如下所示:

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 数据,我正在尝试尽可能优化我的查询。

基本上我需要选择带有一些 where 子句的字段,并在 field 上按降序排列rank

例如,下面是几个 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很重要。所以我很困惑是否应该在单列或多列上添加索引。

谁能建议我最好的解决方案。

4

1 回答 1

2

您的关键问题是超过 950k 行您的status列有多达 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 语法,特别是关于B-Tree 索引特征的部分和以下摘录

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

如果列不构成索引的最左前缀,则 MySQL 不能使用索引。假设您有此处显示的 SELECT 语句:

有时 MySQL 不使用索引,即使索引可用。发生这种情况的一种情况是优化器估计使用索引将需要 MySQL 访问表中很大比例的行。(在这种情况下,表扫描可能会快得多,因为它需要更少的查找。)但是,如果这样的查询使用 LIMIT 只检索一些行,那么 MySQL 无论如何都会使用索引,因为它可以更快地找到在结果中返回的几行。

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

于 2013-06-12T23:49:28.793 回答