Postgres Select ILIKE %text% 在大字符串行上运行缓慢
Postgres Select ILIKE %text% is Slow On Large String Rows
我有一个 table,它只有 7 列,其中一列存储每一行的长文本数据。该文本列数据的平均字符长度约为 1500 个字符。这个 table 有 500.000 行。
当我使用 select 查询而不使用该文本列时,没有问题,查询按预期需要 10 秒。
但是如果我像 Select * from table_1
一样将这个长文本列添加到我的查询中,则需要 3 或 4 分钟才能完成此查询并使用数据适配器填充数据table。
为什么我需要查找那么长的文本列记录?因为我需要像这样使用文本过滤器:
SELECT *
FROM table_1
WHERE longtextcolumn ILIKE ANY (ARRAY['%texttosearch1%', '%texttosearch2%'])
我应该怎么做才能加快进度? Table分区可以解决这个速度问题?或者我应该寻找索引?
包含 col LIKE '%text%'
的 postgreSQL WHERE 子句可以被所谓的 trigram indexes.
支持
对于您的情况,此三元组索引可能会有所帮助。
CREATE INDEX CONCURRENTLY table1_text
ON table1
USING GIN (longtextcolumn gin_trgm_ops)
INCLUDE (col1, col2, col3);
您可以省略 INCLUDE 子句,但如果您从查询中包含您需要的列,它将成为一个 covering index 并进一步加快您的查询。
注意 ILIKE
比 LIKE
运行得慢,但仍然使用三元组索引。
专业提示 为了提高性能,请尽可能避免 SELECT *
。而是命名您想要的列。
这种GIN index is in a postgreSQL extension.您可能需要在使用前加载它。管理您的服务器的人可能需要加载它。
CREATE EXTENSION IF NOT EXISTS pg_trgm;
阅读了这篇 post 中的所有答案后,我开始学习索引,尤其是 Postgres 上的 gin 索引。今天我克服了我的问题。在使用 gin 索引方法之前,我的查询需要 8 分钟才能完成。现在相同的查询需要 50 毫秒。这是一个巨大的性能差异,我想解释一下我为社区所做的每一步。
示例
假设我们有一个名为 table_1 的 table,并且这个 table 有一个名为 long_text 的列。 long_text 列存储长文本数据,例如长度为 1500 个字符的字符串。这个 table_1 有 800.000 行。
第 1 步
Postgres 有一个名为 ts_vector 的数据类型。此 ts_vector 数据类型获取您的长文本并计算其中的单个不同单词(基于语言)并索引其中的单词。因此,我们需要在 table_1 上创建一个 ts_vector 列并转换 long_text 列并从中填充 ts_vector 数据。这将是这样的:
ALTER table table_1
ADD COLUMN long_text_tsv TS_VECTOR;
第 2 步
从我们的 long_text 列填充 ts_vector 数据:
UPDATE table_1 t1
SET long_text_tsv = to_tsvector('english', t1.long_text)
FROM table_1 t2;
第 3 步
为新填充的 long_text_tsv 列创建 gin 索引
CREATE INDEX tsv_index
ON table_1
USING gin(long_text_tsv);
之后您就可以使用新创建和索引的 tsv 数据过滤您的长文本数据
第 4 步
使用 tsvector 数据,您的搜索查询应该是这样的:
SELECT long_text FROM table_1
WHERE long_text_tsv @@ to_tsquery('john<->lennon&music');
ts_vector 数据应按 ts_query 数据类型搜索。在上面的查询中,<-> 表示后跟,& 表示 'AND' 运算符。
通过我解释的这种方法,我的搜索查询速度比旧方法快了 100 倍。
我不确定我是否以正确的方式完成了这一切,但我认为我做得很好,因为现在我的程序中的一切看起来都很好。如果该答案有任何错误,请提醒我。
我有一个 table,它只有 7 列,其中一列存储每一行的长文本数据。该文本列数据的平均字符长度约为 1500 个字符。这个 table 有 500.000 行。
当我使用 select 查询而不使用该文本列时,没有问题,查询按预期需要 10 秒。
但是如果我像 Select * from table_1
一样将这个长文本列添加到我的查询中,则需要 3 或 4 分钟才能完成此查询并使用数据适配器填充数据table。
为什么我需要查找那么长的文本列记录?因为我需要像这样使用文本过滤器:
SELECT *
FROM table_1
WHERE longtextcolumn ILIKE ANY (ARRAY['%texttosearch1%', '%texttosearch2%'])
我应该怎么做才能加快进度? Table分区可以解决这个速度问题?或者我应该寻找索引?
包含 col LIKE '%text%'
的 postgreSQL WHERE 子句可以被所谓的 trigram indexes.
对于您的情况,此三元组索引可能会有所帮助。
CREATE INDEX CONCURRENTLY table1_text
ON table1
USING GIN (longtextcolumn gin_trgm_ops)
INCLUDE (col1, col2, col3);
您可以省略 INCLUDE 子句,但如果您从查询中包含您需要的列,它将成为一个 covering index 并进一步加快您的查询。
注意 ILIKE
比 LIKE
运行得慢,但仍然使用三元组索引。
专业提示 为了提高性能,请尽可能避免 SELECT *
。而是命名您想要的列。
这种GIN index is in a postgreSQL extension.您可能需要在使用前加载它。管理您的服务器的人可能需要加载它。
CREATE EXTENSION IF NOT EXISTS pg_trgm;
阅读了这篇 post 中的所有答案后,我开始学习索引,尤其是 Postgres 上的 gin 索引。今天我克服了我的问题。在使用 gin 索引方法之前,我的查询需要 8 分钟才能完成。现在相同的查询需要 50 毫秒。这是一个巨大的性能差异,我想解释一下我为社区所做的每一步。
示例
假设我们有一个名为 table_1 的 table,并且这个 table 有一个名为 long_text 的列。 long_text 列存储长文本数据,例如长度为 1500 个字符的字符串。这个 table_1 有 800.000 行。
第 1 步
Postgres 有一个名为 ts_vector 的数据类型。此 ts_vector 数据类型获取您的长文本并计算其中的单个不同单词(基于语言)并索引其中的单词。因此,我们需要在 table_1 上创建一个 ts_vector 列并转换 long_text 列并从中填充 ts_vector 数据。这将是这样的:
ALTER table table_1
ADD COLUMN long_text_tsv TS_VECTOR;
第 2 步
从我们的 long_text 列填充 ts_vector 数据:
UPDATE table_1 t1
SET long_text_tsv = to_tsvector('english', t1.long_text)
FROM table_1 t2;
第 3 步
为新填充的 long_text_tsv 列创建 gin 索引
CREATE INDEX tsv_index
ON table_1
USING gin(long_text_tsv);
之后您就可以使用新创建和索引的 tsv 数据过滤您的长文本数据
第 4 步
使用 tsvector 数据,您的搜索查询应该是这样的:
SELECT long_text FROM table_1
WHERE long_text_tsv @@ to_tsquery('john<->lennon&music');
ts_vector 数据应按 ts_query 数据类型搜索。在上面的查询中,<-> 表示后跟,& 表示 'AND' 运算符。
通过我解释的这种方法,我的搜索查询速度比旧方法快了 100 倍。
我不确定我是否以正确的方式完成了这一切,但我认为我做得很好,因为现在我的程序中的一切看起来都很好。如果该答案有任何错误,请提醒我。