从输入数组生成行

时间:2019-05-10 09:47:27

标签: sql postgresql

假设我有一个表,其中包含许多称为comments的记录,并且每个记录仅包含一个文本主体:

CREATE TABLE comments(id INT NOT NULL, body TEXT NOT NULL, PRIMARY KEY(id));
INSERT INTO comments VALUES (generate_series(1,100), md5(random()::text));

现在,我有一个输入数组,其中包含N个子字符串,并且具有任意长度。例如:

abc
xyzw
123456
not_found

对于每个输入值,我想返回符合特定条件的所有行。

例如,假设该表包含以下记录:

| id | body        |
| -- | ----------- |
| 11 | abcd1234567 |
| 22 | unkown12    |
| 33 | abxyzw      |
| 44 | 12345abc    |
| 55 | found       |

我需要一个返回以下结果的查询:

| substring | comments.id | comments.body |
| --------- | ----------- | ------------- |
| abc       | 11          | abcd1234567   |
| abc       | 44          | 12345abc      |
| xyzw      | 33          | abxyzw        |
| 123456    | 11          | abcd1234567   |

到目前为止,我有这个SQL查询:

SELECT substrings, comments.id, comments.body
FROM unnest(ARRAY[
  'abc',
  'xyzw',
  '123456',
  'not_found'
]) AS substrings
JOIN comments ON comments.id IN (
  SELECT id
  FROM comments as inner_comments
  WHERE inner_comments.body LIKE ('%' || substrings || '%')
);

但是数据库客户端卡住了超过10分钟。我缺少有关联接的信息吗?

请注意,这是我的问题的简化示例。我当前对注释的检查不是LIKE语句,而是具有不同功能(模糊匹配)的复杂开关案例语句。

2 个答案:

答案 0 :(得分:1)

使用IN绕行是不必要的,除非优化程序可以重写它,而且可能无法重写,否则会增加开销。如果没有,那就试试看。

SELECT un.substring,
       comments.id,
       comments.body
       FROM unnest(ARRAY['abc',
                         'xyzw',
                         '123456',
                         'not_found']) un (substring)
       INNER JOIN comments
                  ON comments.body LIKE ('%' || un.substring || '%');

但是由于开头是通配符,因此仍不能在此处使用索引。您可能需要查看Full Text Search,并查看可以使用哪些选项来改善情况。

答案 1 :(得分:0)

基本上,您正在最有可能没有FULLTEXT索引的列中执行FULLTEXT搜索。

您可以尝试的第一步是为“正文” FULLTEXT列建立索引。查看详细信息here,然后使用CONTAINS执行搜索,但是老实说,由于您要执行模糊匹配,因此您不能依靠SQL Server来执行搜索-这样就无法正常工作。您将需要索引服务,例如ElasticSearch,CloudSearch,Azure Search等