【问题标题】:How to optimize query with multiple %如何使用多个 % 优化查询
【发布时间】:2020-02-14 02:08:23
【问题描述】:

请帮我优化下面的Mysql查询

SELECT * FROM `ticket` WHERE `ticket_id` LIKE '%wm%33%' LIMIT 0,1000

该表没有全文索引,我担心当需要始终打开该表时,为该列提供全文索引将花费时间

【问题讨论】:

  • 您使用的是哪个版本的 MySQL?
  • 我觉得这个问题没有提供足够的信息。例如,ticket_id 数据是什么样的?你总是以同样的方式搜索吗?是否可以将 ID 分解为单独的列并编制索引以帮助搜索?
  • 如果没有全文索引,您将无法优化以% 开头的 LIKE 模式。普通索引是 B 树,它们从字符串的开头开始工作。如果模式没有固定的开头,则无法使用索引,您必须进行完整扫描。
  • 但是如果您要匹配的票证部分位于字符串中的固定位置,您可以使用SUBSTR() 为它们创建虚拟列,并将其编入索引。
  • @hamzbond - 发布一些具有代表性的示例数据,并解释您使用 wm33 搜索的方式/原因。如果我们不完全了解问题的背景,我们就无法提供适当的解决方案。

标签: mysql sql optimization indexing


【解决方案1】:

如果您不想使用全文索引,我建议您进行一些基准测试以查看索引是否会对插入性能产生不利影响,您可以重组数据以消除对此类搜索的需要。

我们不知道ticket_id 中的内容,但很明显它具有某种结构。与其对这种合并进行解析和搜索,不如将其拆分成单独的部分并重新组合。

为了使用类似的示例,让我们看一下电子邮件地址。如果您想搜索电子邮件地址为gmail.com 的用户怎么办?这样做的天真方法是......

create table users (
  id serial primary key,
  email varchar(255) not null unique
);

select * from users
where email like '%@gmail.com'

存在性能问题。还有匹配user@subdomain.gmail.com的问题。 like '%gmail.com'自带问题,会匹配person@thingmail.com

相反,使用generated columns,我们可以将域与电子邮件地址分开并为其编制索引。

create table users (
  id serial primary key,
  email varchar(255) not null unique,
  domain varchar(255) as (
    substring_index(substring_index(email, '@', -1), '.', -2)
  ),

  index(domain)
);

现在匹配域是一个简单的索引相等检查。

select * from users
where domain = 'gmail.com'

我希望您可以为您的ticket_id 做类似的事情。这是否值得努力,需要进行一些基准测试,还需要考虑复杂性:全文索引更简单、更灵活。

dbfiddle

【讨论】:

    【解决方案2】:
    WHERE `ticket_id` LIKE '%wm%33%'
    

    可以替换为

    WHERE LOCATE('wm', ticket_id) < LOCATE('33', ticket_id)(见下文)

    我认为它更便宜。

    附言。无索引可能有助于提高此类搜索性能...


    Barmar:如果找不到字符串,LOCATE() 返回 0,因此这将返回不包含 wm 的行。改成

    LOCATE('wm', ticket_id) BETWEEN 1 AND LOCATE('33', ticket_id)

    确实如此。

    【讨论】:

    • LOCATE() 如果找不到字符串,则返回0,因此这将返回不包含wm 的行。将其更改为LOCATE('wm', ticket_id) BETWEEN 1 AND LOCATE('33', ticket_id)
    • 为什么不可分割的LOCATE 应该比LIKE 快?两者都必须阅读每一行行并执行不可索引的操作。
    • @RickJames 如果 LOCATE/INSTR 没有映射到 LIKE/REGEXP,它们的成本会更低......有时甚至为 promille 节省可能是有意义的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-07-06
    • 1970-01-01
    • 1970-01-01
    • 2022-01-27
    • 2012-02-15
    • 1970-01-01
    • 2023-03-11
    相关资源
    最近更新 更多