我的表结构如下所示:
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;
在上表中,字段rank
和status
的整数值分别介于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
非常重要。所以我很想知道是否应该在单列或多列上添加索引。
任何人都可以向我推荐最佳解决方案。
答案 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 )
是有效的(事实上,由于引用整数数据类型而不是将它们指定为,因此我在过去遇到了一些奇怪的问题数字)