我有一个包含四列的单个表......
`id` INT(11) NOT NULL AUTO_INCREMENT
`tid` INT(11) NOT NULL
`cid` INT(11) NOT NULL
`name` NVARCHAR(4096) NULL DEFAULT NULL
id 是唯一的主键。其他列不是唯一的。
我想返回具有特定 tid 和 cid 值的所有 id 值的列表,并按名称排序。所以这......
select id
from myTable
where cid = 1 && tid = 1
order by name
表中大约有125k记录,应该有大约50k的记录符合这个标准。所有四列都有单独的索引。
在我的机器上,查询大约需要140毫秒才能运行。我需要将其降低到大约20ms或更好。我认为解决方案是添加一个新的覆盖索引,该索引按照 cid , tid 和名称的顺序定义。但是没有任何区别。
有什么想法吗?我的覆盖索引是否设置不正确?
答案 0 :(得分:2)
我认为查询和表定义本身存在一些问题。
Table.name
是一个4K char列您根据要存储字符串的列进行排序。为了按字符串排序,必须执行字符串比较。字符串比较往往是一个缓慢的操作,并且考虑到您使用的列的大小,它很可能会导致明显的性能损失。
我们没有说明您的name
列的内容,而且似乎很难想到需要 多个字符的实际名称。
如果此字符串包含几个概念上不同的数据,则可能应将列拆分为多个单独的列(如果可能),然后根据需要进行标准化。
如果您可以将该列的内容分解为多个较小的列然后使用它们,那么字符串比较虽然仍然很昂贵,但会更快'仅仅因为被比较的字符串将比他们现在的字符串短得多。
另一件需要考虑的事情是,如果您可以通过完全避免字符串比较来优化搜索,或者通过避免将导致全表扫描的查询来优化搜索,尽管您已经定义了索引。< / p>
为此,您应该在查询中使用explain
,以便更好地了解Query Execution Plan
引用文档(我的重点):
取决于表,列,索引和的详细信息 在你的WHERE子句中的条件,MySQL优化器会考虑很多 有效执行SQL中涉及的查找的技术 查询。 ...你的目标是... 学习SQL语法和索引技术,以便在看到一些效率低下的操作时改进计划。
您已澄清您的name
列实际上是用户注释。在这种情况下,我认为您应该考虑以下内容(在添加中已经提到过):
text
类型,您不必担心用户论文会在没有警告的情况下被截断(除非GUI已强制执行对用户的输入长度限制相同)答案 1 :(得分:0)
INDEX(cid, tid, name)
会大大加快查询速度。
但是,假设name
是文明长度,例如低于255.如果您必须有更长的name
,那么这是您可以做的最好的事情:
INDEX(cid, tid) -- (in either order)
不,“前缀”索引不帮助:INDEX(cid, tid, name(99))
。前缀索引对ORDER BY
无用。
所有四列都有单独的索引。
单个索引不与复合索引相同。有时他们会更好;通常他们不是。
中提供了更多详细信息