我有一个有四列的单人桌子……
`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和name定义的.虽然没有任何区别.
有任何想法吗?我的覆盖索引是否设置错误?
解决方法:
我认为查询和表定义本身存在一些问题.
> Table.name是4K char列
>查询按该列排序
您正在根据存储字符串的列进行排序.为了按字符串排序,必须执行字符串比较.字符串比较往往是一个缓慢的操作,并且考虑到您正在使用的列的大小,它很可能会导致明显的性能损失.
我们没有指示您的名称列的内容,似乎很难想到需要许多字符的实际名称.
如果此字符串具有几个概念上不同的数据,则可能应将列拆分为多个单独的列(如果可能),然后根据需要进行标准化.
如果您可以将该列的内容分解为多个较小的列,然后使用它们,字符串比较虽然仍然很昂贵,但“更快”只是因为被比较的字符串将比现在的字符串短得多.
另一件需要考虑的事情是,如果您可以通过完全避免字符串比较来优化搜索,或者通过避免将导致全表扫描的查询来优化搜索,尽管您已经定义了索引.
为此,您应该在查询中使用说明,以便更好地了解Query Execution Plan
引用文档(我的重点):
Depending on the details of your tables, columns, indexes, and the
conditions in your WHERE clause, the MySQL optimizer considers many
techniques to efficiently perform the lookups involved in an SQL
query. … Your goals are … to learn the SQL syntax and indexing techniques to improve the plan if you see some inefficient operations.
编辑1
您已经澄清了您的名称列实际上是用户注释.在这种情况下,我认为你应该考虑以下(除了已经提到的内容):
>将列重命名为与其实际内容相关的内容
>从列中删除索引
>不要使用该列进行搜索,排序或任何其他操作,而不仅仅是选择它来显示它(如果它需要用于其他任何事情,那就非常罕见了,恕我直言.)
>(可选)考虑将列更改为文本类型,您不必担心在没有警告的情况下截断用户文章(除非GUI对用户强制执行相同的输入长度限制)