Answers:
您的查询几乎是最佳的。语法不会变短,查询不会变快:
SELECT name
FROM spelers
WHERE name LIKE 'B%' OR name LIKE 'D%'
ORDER BY 1;
如果您确实想缩短语法,请使用带有分支的正则表达式:
...
WHERE name ~ '^(B|D).*'
或稍快一点,使用一个字符类:
...
WHERE name ~ '^[BD].*'
SIMILAR TO
对我而言,没有索引的快速测试所产生的结果比任何一种情况下都更快。
有了适当的B树索引,就可以在LIKE
这场比赛中胜出几个数量级。
如果您担心性能,请为更大的表创建这样的索引:
CREATE INDEX spelers_name_special_idx ON spelers (name text_pattern_ops);
使这种查询的速度提高几个数量级。特殊注意事项适用于特定于语言环境的排序顺序。在手册中阅读有关操作符类的更多信息。如果您使用标准的“ C”语言环境(大多数人不使用),则将使用纯索引(具有默认的运算符类)。
这样的索引仅适用于左锚模式(从字符串开头开始匹配)。
SIMILAR TO
或带有基本左锚表达式的正则表达式也可以使用此索引。但不包含分支(B|D)
或字符类[BD]
(至少在我对PostgreSQL 9.0的测试中)。
Trigram匹配或文本搜索使用特殊的GIN或GiST索引。
LIKE
(~~
)简单,快速,但功能有限。
ILIKE
(~~*
)不区分大小写的变体。
pg_trgm扩展了两者的索引支持。
~
(正则表达式匹配)功能强大但更复杂,除基本表达式外,其他任何东西的运行速度都可能很慢。
SIMILAR TO
仅仅是毫无意义的。LIKE
正则表达式的特殊混血。我从不使用它。见下文。
%是附加模块提供的“相似”运算符pg_trgm
。见下文。
@@
是文本搜索运算符。见下文。
从PostgreSQL 9.1开始,您可以方便扩展使用GIN或GiST索引pg_trgm
为任何 LIKE
/ ILIKE
模式(以及带有的简单正则表达式模式~
)提供索引支持。
详细信息,示例和链接:
pg_trgm
还提供以下运算符:
%
-“相似性”运算符 <%
(换向器:%>
)-Postgres 9.6或更高版本中的“ word_similarity”运算符<<%
(换向器:%>>
)-Postgres 11或更高版本中的“ strict_word_similarity”运算符是与单独的基础结构和索引类型匹配的一种特殊类型的模式。它使用字典和词干,是在文档中查找单词的好工具,特别是对于自然语言。
还支持前缀匹配:
从Postgres 9.6开始,还有短语搜索:
请考虑手册中的介绍以及操作员和功能的概述。
附加模块Fuzzystrmatch提供了更多选项,但是性能通常不如上述所有。
特别地,levenshtein()
功能的各种实现可以是有用的。
~
)总是比快SIMILAR TO
?答案很简单。SIMILAR TO
表达式在内部被重写为正则表达式。因此,对于每个SIMILAR TO
表达式,至少有一个更快的正则表达式(这节省了重写表达式的开销)。使用SIMILAR TO
ever不会提高性能。
无论如何,可以使用LIKE
(~~
)完成的简单表达式都更快LIKE
。
SIMILAR TO
仅在PostgreSQL中受支持,因为它最终出现在SQL标准的早期草案中。他们仍然没有摆脱它。但是有计划将其删除,而改为包含正则表达式匹配项-或我听说。
EXPLAIN ANALYZE
揭示它。自己尝试使用任何桌子!
EXPLAIN ANALYZE SELECT * FROM spelers WHERE name SIMILAR TO 'B%';
揭示了:
...
Seq Scan on spelers (cost= ...
Filter: (name ~ '^(?:B.*)$'::text)
SIMILAR TO
已使用正则表达式(~
)重写。
但EXPLAIN ANALYZE
揭示更多。尝试使用上述索引:
EXPLAIN ANALYZE SELECT * FROM spelers WHERE name ~ '^B.*;
揭示了:
...
-> Bitmap Heap Scan on spelers (cost= ...
Filter: (name ~ '^B.*'::text)
-> Bitmap Index Scan on spelers_name_text_pattern_ops_idx (cost= ...
Index Cond: ((prod ~>=~ 'B'::text) AND (prod ~<~ 'C'::text))
在内部,与未识别语言代码的索引(text_pattern_ops
或使用区域C
)简单的左锚定表达式用这些文字图案运营商改写为:~>=~
,~<=~
,~>~
,~<~
。这是的情况下~
,~~
或SIMILAR TO
相似。
varchar
具有varchar_pattern_ops
或char
具有的类型上的索引也是如此bpchar_pattern_ops
。
因此,将其应用于原始问题,这是最快的方法:
SELECT name
FROM spelers
WHERE name ~>=~ 'B' AND name ~<~ 'C'
OR name ~>=~ 'D' AND name ~<~ 'E'
ORDER BY 1;
当然,如果您碰巧要搜索相邻的缩写,则可以进一步简化:
WHERE name ~>=~ 'B' AND name ~<~ 'D' -- strings starting with B or C
与~
或的普通使用相比,收益~~
很小。如果性能不是您的首要要求,那么您应该坚持使用标准操作员-得出问题中已有的内容。
similar
一次扫描吗?
EXPLAIN ANALYZE
显示2个位图索引扫描。多个位图索引扫描可以相当快速地组合在一起。
OR
用UNION ALL
或更换name LIKE 'B%'
与 name >= 'B' AND name <'C'
Postgres里?
UNION
不会,但是,是的,将范围合并为一个WHERE
子句将加快查询速度。我在答案中添加了更多内容。当然,您必须考虑到您的语言环境。区域设置感知搜索总是较慢。
如何在表中添加一列。根据您的实际要求:
person_name_start_with_B_or_D (Boolean)
person_name_start_with_char CHAR(1)
person_name_start_with VARCHAR(30)
PostgreSQL 在SQL Server中不支持基表中的计算列,但可以通过触发器维护新列。显然,该新列将被索引。
CREATE INDEX spelers_name_initial_idx ON spelers (left(name, 1));
在其条件下与表达式匹配的查询可以利用此索引。
这样,在创建或修改数据时会导致性能下降,因此可能仅适用于低活动性环境(即写入次数少于读取次数)。
你可以试试
SELECT s.name
FROM spelers s
WHERE s.name SIMILAR TO '(B|D)%'
ORDER BY s.name
我不知道上面或您的原始表达式是否在Postgres中都是可修饰的。
如果您创建建议的索引,也将有兴趣了解它与其他选项的比较。
SELECT name
FROM spelers
WHERE name >= 'B' AND name < 'C'
UNION ALL
SELECT name
FROM spelers
WHERE name >= 'D' AND name < 'E'
ORDER BY name
很老的问题,但是我找到了解决这个问题的另一种快速解决方案:
SELECT s.name
FROM spelers s
WHERE ascii(s.name) in (ascii('B'),ascii('D'))
ORDER BY 1
由于函数ascii()仅查看字符串的第一个字符。
(name)
吗?
为了检查首字母缩写,我经常使用强制转换为"char"
(带有双引号)。它不是便携式的,但速度很快。在内部,它简单地删除文本并返回第一个字符,并且“ char”比较操作非常快,因为类型为1字节固定长度:
SELECT s.name
FROM spelers s
WHERE s.name::"char" =ANY( ARRAY[ "char" 'B', 'D' ] )
ORDER BY 1
请注意,强制转换为to "char"
的速度比ascii()
@ Sole021的速度快,但它与UTF8不兼容(或与此相关的任何其他编码),仅返回第一个字节,因此仅应在与普通旧7比较的情况下使用位ASCII字符。
进行单个字符比较可能更快:
SUBSTR(s.name,1,1)='B' OR SUBSTR(s.name,1,1)='D'
column LIKE 'B%'
比在该列上使用子字符串函数更有效。
s.name
索引了吗?