【问题标题】:MySQL indexes not used on LIKE for INT?MySQL 索引未在 LIKE for INT 上使用?
【发布时间】:2018-01-02 00:23:09
【问题描述】:

我不知道这是错误还是功能,或者我做错了什么。我继承了一个有几十万行的 MySQL 数据库。该表包括作为 VARCHAR 的字段“full_name”和作为 INT 的“workpack”。

此表的用途之一是在人们开始填写 HTML 表单时提供自动完成功能,这在上述字段中提供。我注意到,当输入“full_name”时,自动完成出现并更新得非常快,但是当为“workpack”输入整数时,自动完成出现和更新的速度很慢,几乎无法使用。

这两个字段都有索引,查询结构的简化示例如下:

SELECT distinct full_name       
FROM xx.xx
WHERE full_name LIKE 'Joe Bl%';

解释表明这是按预期使用索引“full_name”。

对“工作包”的几乎相同的查询:

SELECT distinct workpack
FROM xx.xx
WHERE workpack LIKE '153%';

这里的解释表明它没有使用索引“工作包”,即使我使用了 FORCE INDEX。

因为我能看到的唯一区别是一个是 INT,一个是 VARCHAR,所以我决定通过创建表的本地副本并将“workpack”的数据类型更改为 VARCHAR 来进行实验。有效!也许对某些人来说并不奇怪,但我想知道为什么会发生这种情况。显然,我的“工作包”数据应该存储为 INT,因为它就是这样,但要让我的自动完成功能以合理的方式工作,似乎我需要将其更改为 VARCHAR。我意识到 LIKE 是一个字符串函数,但是鉴于 LIKE 函数仍然适用于 INT,是否有逻辑上的技术原因导致它无法使用索引仅仅因为它是一个 INT?

【问题讨论】:

  • 当您对 INT 列应用 LIKE 时,会对 VarChar 进行隐式类型转换(这会阻止在所有 DBMS 中使用索引)。而LIKE '153% 表示您没有数值,而是一串数字(如电话号码)。
  • 如果workpack 从未打算用于数学运算,那么即使它看起来像数字,也没有理由不在数据库中将其更改为VARCHAR。如果它用于数学,您可以通过添加 VARCHAR 类型的重复列来快速交易数据量
  • 它没有使用索引有一个完全有效的逻辑和技术原因,你的结论是一个谬误。字符串是数字。每个“字母”分配 1 - 4 个字节,具体取决于使用的编码。这是一个数字,内部。当您索引某些文本时,数字序列 存储在有序数据结构中。当您索引一个整数时,一个数字(一个数字,即1 - 8 字节长)存储在一个有序的数据结构中。所以,你有它 - 你告诉 MySQL 将这个 1 - 8 字节的数字分解成一个在索引中找不到的数字序列。

标签: mysql sql select indexing


【解决方案1】:

索引本质上是一个排序的数据结构,它从列的映射到包含它的行。因此,它只能在您的查询使用实际值时使用,而不是对其进行一些转换(例如将int 转换为varchar)。

此类问题的一个巧妙解决方案(自 MySQL 5.7.6 起可用)是添加一个自动生成的列,其唯一目的是对其进行索引并在此类查询中使用它。它可能会浪费一些空间(因为您拥有相同数据的两个副本 - 原始数据和计算列),但如果您的应用程序大量使用此查询,那么它可能是值得的:

CREATE TABLE xx.xx (
    full_name VARCHAR(100),
    workpack INT,
    workpack_str CHAR(20) AS CAST(workpack AS CHAR) STORED, 
    INDEX(full_name),
    INDEX workpack_str 
)

【讨论】:

    【解决方案2】:

    索引在这里不合适,因为您将它转换为字符串。如果你用它们的值或它们的字符串表示对一个数字列表进行排序,结果会有所不同。以 125 和 1234 为例。按值排序时,您会得到:

    • 125
    • 1234

    当按字符串表示排序时,您会得到:

    • 1234
    • 125

    所以索引在您的情况下是无用的,因为它是值顺序(因为您的字段是 int),而您的搜索需要字符串顺序(因为您使用 like 来查找一些字符串前缀)。 (请记住,索引实际上只是一个排序列表)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-06-22
      • 1970-01-01
      • 1970-01-01
      • 2019-09-05
      • 2012-09-26
      • 2011-04-09
      • 2017-08-28
      相关资源
      最近更新 更多