使用select时,两列上的MySQL索引

时间:2014-12-18 16:09:27

标签: mysql sql innodb sphinx

我在这里有一个非常蹩脚的问题,所以希望你们所有的MySQL专家都能为我解答这个问题:)

我有这种类型的表:

+--------+------------------+------+-----+---------+-------+
| Field  | Type             | Null | Key | Default | Extra |
+--------+------------------+------+-----+---------+-------+
| id     | int(10) unsigned | NO   | PRI | NULL    |       |
| abc_1  | char(1)          | NO   | MUL | NULL    |       |
| abc_2  | char(2)          | NO   | MUL | NULL    |       |
| abc_3  | char(3)          | NO   | MUL | NULL    |       |
| abc_4  | char(4)          | NO   | MUL | NULL    |       |
| abc_5  | char(5)          | NO   | MUL | NULL    |       |
| abc_6  | char(6)          | NO   | MUL | NULL    |       |
| abc_7  | char(7)          | NO   | MUL | NULL    |       |
| abc_8  | char(8)          | NO   | MUL | NULL    |       |
| abc_9  | char(9)          | NO   | MUL | NULL    |       |
| abc_10 | char(10)         | NO   | MUL | NULL    |       |
+--------+------------------+------+-----+---------+-------+

此表上有很多(数百万)记录。

所有查询如下:

SELECT `id` FROM `tbl` WHERE `abc_1` = 'a' LIMIT 10;
SELECT `id` FROM `tbl` WHERE `abc_2` = 'zz' LIMIT 10;
SELECT `id` FROM `tbl` WHERE `abc_3` = 'xxx' LIMIT 10;

等等。

表有InnoDB引擎,abc列的排序规则为latin1_general_ci

所以我的问题很简单:我应该添加哪个索引以使这些类型的查询运行得更快?

仅限单列(例如abc_1abc_2等), 两列(例如:idabc_1idabc_2等等) 或两列的顺序相反(例如:abc_1idabc_2id)?

我想最后一个变体是最好的(abc_1 + id)。 我可以测试和测试所有变体,但由于它是大表,因此需要花费大量时间来创建新索引,所以我想首先询问您的意见。

也许有人可以建议任何缓存技术如何更快地运行这些类型的查询,而不直接涉及MySQL? 我听说过这种类型的查询可以使用Sphinx,例如:添加abc列作为属性?也许somone有经验吗?

提前谢谢大家!

3 个答案:

答案 0 :(得分:0)

这些查询的最佳索引是复合索引:table(abc_1, id)table(abc_2, id)table(abc_3, id)(依此类推)。我相信这是你的最后一个选择。

这些索引“涵盖”您建议的查询。这意味着索引本身可以用于查询,而不是从数据页加载数据。

如果您混合使用所有这些查询,那么您需要确保有足够的内存将索引存储在内存中。

答案 1 :(得分:0)

我会将id设为主键,然后单独索引abc_ *列。 MySQL中的二级索引与其对应的主键值一起存储,因此实际上它们可以"参见"主键。在空间优化和避免大量冗余方面,我只需将id作为主键,然后单独索引abc_ *列。

就性能而言,你拥有的两个最大的杠杆是缓冲池http://dev.mysql.com/doc/refman/5.6/en/innodb-buffer-pool.html ...特别是innodb_buffer_pool_size和innodb_buffer_pool_instances)以及你自己提交的查询。如果您的abc_ *列已编制索引(并且id是主键),则您建议的查询将非常有效。但是你要注意慢速查询日志,并且可能安装Percona MySQL并使用他们的pt-query-digest工具来分析你的慢查询(例如http://www.percona.com/doc/percona-toolkit/pt-query-digest.html)。后者更具可选性,考虑到您提出的疑问,首先可能没有必要。

不过,我考虑过的一件事就是abc_ *列的长度。如果它们相当长,您可以尝试应用它们的MD5,或者将数据标准化一点,并简单地存储id(将实际文本值放在查找表中)。后者不一定是必要的(原谅那个精彩的句子),但如果我在abc_ *列中有特别长的文本值,我可能会考虑它。

答案 2 :(得分:0)

如果您没有交叉 - 即每列中的值,则每列都是唯一的,例如' zz'只能在abc_2中找到,而不是第3列等。 ...然后建议MySQL中的全文索引可以正常工作。您只进行单字查找,因此速度非常快。甚至是innodb中新的全文支持。 (全文中使用的倒排索引非常适合单字查找)

如果您确实需要将结果限制为特定列,那么外部搜索引擎可能会更好。你建议使用Sphinx可以工作,但大多数人都可以满足这些简单的要求。外部索引的一个很好的功能,可以在不更改数据库表的情况下设置索引,因此可以在表上设置一个sphinx索引,不用触摸您的实际表。 (在Sphinx中,您不需要将列作为属性,将它们保留为字段,您仍然可以进行全文查询。使用较少的内存,索引将更快。) ... sphinx将运行此类查询,几乎始终不到1毫秒,无论索引大小如何,以及非常适度的服务器。