0

我有一个有四列的表......

 `id` INT(11) NOT NULL AUTO_INCREMENT   
 `tid` INT(11) NOT NULL
 `cid` INT(11) NOT NULL
 `name` NVARCHAR(4096) NULL DEFAULT NULL

id是唯一的主键。其他列不是唯一的。

我想返回具有特定tidcid值并按名称排序的所有id值的列表。所以这...

 select id
 from myTable
 where cid = 1 && tid = 1
 order by name

表中有大约 125k 条记录,并且应该有大约 50k 条恰好符合此条件。所有四列都有单独的索引。

在我的机器上,查询运行大约需要 140 毫秒。我需要把它降低到大约 20 毫秒或更好。我认为解决方案是添加一个新的覆盖索引,该索引按cidtid和 name 的顺序定义。虽然没有任何区别。

有任何想法吗?我的覆盖指数是否设置不正确?

4

2 回答 2

2

我认为查询和表定义本身存在一些问题。

  • Table.name是一个 4K 字符列
  • 查询按该列排序

您正在根据存储字符串的列进行排序。为了按字符串排序,必须执行字符串比较。字符串比较往往是一个缓慢的操作,并且考虑到您正在使用的列的大小,它很可能会导致明显的性能损失。

我们不知道您的name专栏的内容,而且似乎很难想出一个需要这么多字符的实际名称。

如果这个字符串有几个概念上不同的数据,如果可能的话,也许应该将该列分解为多个单独的列,然后适当地进行规范化。

如果您可以将该列的内容分成多个较小的内容,然后使用它们,那么字符串比较虽然仍然很昂贵,但会“更快”,因为被比较的字符串将比现在短得多。

要考虑的另一件事是,您是否可以通过完全避免字符串比较或避免会导致全表扫描的查询来优化搜索,尽管您已经定义了索引。

为此,您应该考虑explain与查询一起使用,以便更好地了解查询执行计划

引用文档(我的重点):

根据您的表、列、索引和 WHERE 子句中的条件的详细信息, MySQL 优化器会考虑许多技术来有效地执行 SQL 查询中涉及的查找。...您的目标是...学习 SQL 语法和索引技术,以在您发现一些低效操作时改进计划。


编辑 1

您已经澄清您的name专栏实际上是用于用户注释的。在这种情况下,我认为您应该考虑以下内容(除了已经提到的内容):

  1. 将列重命名为与其实际内容相关的名称
  2. 从列中删除索引
  3. 不要将该列用于搜索、排序或任何其他操作,不仅仅是选择它来显示它(如果它需要用于其他任何事情,恕我直言,这是非常罕见的。)
  4. 或者,考虑将列更改为一种text类型,您不必担心用户文章会在没有警告的情况下被截断(除非 GUI 对用户强制执行相同的输入长度限制)
于 2015-10-19T04:42:14.700 回答
0
INDEX(cid, tid, name)

将大大加快查询速度。

但是,假设name是文明长度,例如 255 以下。如果你必须有更长的name,那么这是你能做的最好的:

INDEX(cid, tid)  -- (in either order)

不,“前缀”索引无济于事INDEX(cid, tid, name(99)). 前缀索引对ORDER BY.

所有四列都有单独的索引。

单个索引复合索引不同。有时它们更好;通常他们不是。

我在我的Index Cookbook中提供了更多详细信息。

于 2015-11-01T05:07:19.407 回答