簡體   English   中英

如何在文本列的 substring 上創建索引?

[英]How can I create an index on a substring of a text column?

我經常需要根據文本列中是否存在 substring 來過濾特定表中的記錄。 具體來說,我需要排除包含/的記錄。

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

WHERE table_name.text_col NOT LIKE "%/%"

我的直覺是,在每條記錄的字符串中搜索此 substring 需要很長時間(相對而言),並且可以通過某種方式進行索引來改進。 我可以創建一個新的二進制索引列並根據文本列是否包含/來填充它,但我想知道是否有更簡潔的解決方案?

我發現這個問題指的是LEFT()樣式的解決方案,但我不理解語法,我正在尋找可以處理字符串中任何位置的 substring 的東西。

可以創建一個持久存儲信息的計算列:

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;

DB Fiddle 上的演示

過濾預先計算的值應該已經提高了性能。

在 boolean 列上創建索引不一定有幫助,因為只有三個可能的值(0、1、null)。 除非這些值分布非常不均勻,否則數據庫執行完整掃描通常會更快。 另一方面,如果您的搜索條件比您顯示的更多,您可能希望將此列包含在多列索引中。

真正的問題是是否需要檢查整個表,以及是否有某種方法可以通過索引限制行數。

首先,讓我們決定這樣的索引是否會被使用。 作為經驗法則,如果超過 20% 的表與某個索引匹配,則不會使用該索引。 (“20”因月相而異。)邏輯是在索引的 BTree 和數據的 BTree 之間跳動需要一些成本。 如果行數不多,那么這種彈跳是值得的——也就是說,當索引是“選擇性的”時。

因此,如果超過 20% 的行有“/”,則所有建議都不會有效。 LOCATE可能比LIKE更有效; 一個REGEXP可能比任何一個都慢。 盡管如此,查詢中的主要成本將不得不查看每一行。

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

如果真正的測試是WHERE x LIKE '%/%' AND... ,那么我們需要查看測試的次要部分。 可能即使是對“/”的非選擇性測試也可以有效地與測試的其他部分結合起來。

底線:給我們完整的圖片,加上一些統計數據。

也許LOCATE可以幫助你。

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

LOCATE返回 0 時,表示在字符串中找不到 substring。 更多信息請訪問https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_locate

您要求LEFT() ,這不是您要找的。 此 function 從字符串的開頭返回 substring。 語法很簡單, https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_left

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM