【问题标题】:How can I create an index on a substring of a text column?如何在文本列的子字符串上创建索引?
【发布时间】:2021-04-07 17:47:32
【问题描述】:

我经常需要根据文本列中是否存在子字符串来过滤特定表中的记录。具体来说,我需要排除包含/ 的记录。

我目前使用WHERE 语句,例如:

WHERE table_name.text_col NOT LIKE "%/%"

我的直觉是,在每条记录的字符串中搜索该子字符串需要很长时间(相对而言),并且可以通过某种方式进行索引来改进。我可以创建一个新的二进制索引列并根据文本列是否包含 / 来填充它,但我想知道是否有更简洁的解决方案?

我发现this 问题指的是LEFT() 风格的解决方案,但我不理解语法,我正在寻找可以处理字符串中任何位置的子字符串的东西。

【问题讨论】:

    标签: mysql sql query-optimization sql-like calculated-columns


    【解决方案1】:

    也许LOCATE可以帮到你。

    WHERE LOCATE('/', table_name.text_col) = 0 
    

    LOCATE 返回 0 表示在字符串中找不到子字符串。更多信息请访问https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_locate

    您要求LEFT(),这不是您要找的。此函数从字符串的开头返回子字符串。语法很简单,https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_left

    【讨论】:

    • 这还需要检查所有记录(全表扫描)以获得结果。
    • 谢谢。这会比我目前的WHERE 声明更快吗?顺便说一句 - 我没有考虑LEFT() 解决方案,因为我需要一些“可以处理字符串中任何位置的子字符串”的东西。
    • @Luuk - 谢谢,你回答了我的问题 :) 我这里有索引选项吗?
    • 如果你真的需要查询这个,并且你不能更改该列内的数据,那么你自己的解决方案(创建一个'二进制索引列')应该是最好的。
    【解决方案2】:

    可以创建一个永久存储信息的计算列:

    alter table table_name 
        add column text_has_slash tinyint
        generated always as (text_col like '%/%')
        stored
    ;
    

    或者,如果您想将 null 值视为负数:

        generated always as (coalesce(text_col like '%/%', 0))
    

    列值被计算并存储在表中(当值改变时由数据库自动更新)。

    现在您可以在查询中使用该列:

    select * from table_name where not text_has_slash;
    

    Demo on DB Fiddle

    过滤预先计算的值应该已经提高了性能。

    在布尔列上创建索引不一定有帮助,因为只有三个可能的值(0、1、null)。除非这些值分布非常不均匀,否则数据库执行完整扫描通常会更快。另一方面,如果您的搜索条件比您显示的更多,您可能希望将此列包含在多列索引中。

    【讨论】:

      【解决方案3】:

      真正的问题是是否需要检查整个表,以及是否有某种方法可以通过索引限制行数。

      首先,让我们决定是否会使用这样的索引。作为经验法则,如果超过 20% 的表与某个索引匹配,则不会使用该索引。 (“20”因月相而异。)逻辑是在索引的 BTree 和数据的 BTree 之间跳动会花费一些成本。如果行数不多,那么这种弹跳是值得的——即当索引是“选择性的”时。

      因此,如果超过 20% 的行有“/”,则所有建议都不会有效。 LOCATE 可能比LIKE 更有效率; REGEXP 可能比任何一个都慢。尽管如此,查询中的 main 成本将不得不查看 每一 行。

      另一方面,如果只有很少的行有“/”,那么任何预计算索引都是有益的。

      如果真正的测试是WHERE x LIKE '%/%' AND ...,那么我们需要看一下测试的次要部分。 可能即使是对“/”的非选择性测试也可以有效地与测试的其他部分结合起来。

      底线:给我们完整的图片,加上一些统计数据。

      【讨论】:

      • 我会将索引的有用性置于 20% 以下,可能为 5%,但仅此而已。
      猜你喜欢
      • 2021-03-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-04
      • 1970-01-01
      • 2012-01-17
      • 2012-08-19
      • 1970-01-01
      相关资源
      最近更新 更多