一尘不染

MySQL select似乎很慢,但不知道如何改进?

sql

我有一个四列的表格…

 `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以此顺序定义。没什么区别。

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


阅读 209

收藏
2021-03-17

共1个答案

一尘不染

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

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

您基于存储字符串的列进行排序。为了按字符串排序,必须执行字符串比较。字符串比较通常是一个缓慢的操作,并且鉴于您正在使用的列的大小,很可能会导致明显的性能下降。

我们没有表明您的name专栏内容,并且似乎很难想到一个需要 这么 多字符的实际名称。

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

如果您可以将该列的内容分成多个较小的内容,然后使用它们,则字符串比较尽管仍然很昂贵,但“比较快”,这仅仅是因为所比较的字符串将比现在的字符串短得多。

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

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

引用文档(我的重点):

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


编辑1

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

  1. 将列重命名为与其实际内容相关的内容
  2. 从列中删除索引
  3. 千万 不能 使用搜索,排序,或不仅仅是选择它来显示它的其他任何其他操作该列(这将会是 非常 罕见的,如果它需要被用来为别的,恕我直言。)
  4. (可选)考虑将列更改为text类型,您不必担心用户 文章会 在没有警告的情况下被截断(除非GUI对用户实施了相同的输入长度限制)
2021-03-17