我需要从PostgreSQL DB中选择记录。让我们说这是我的表(非常简化)
Table1
ID Name Surname
1 Stan Marsh
2 Randy Marsh
3 Marry Christmas
我需要通过Name + Surname过滤的结果,以便当过滤字符串例如" ar"时。返回所有记录,并且" sh"只会先返回两个。我正在使用:
select * FROM Table1
WHERE concat(Table1.Name::text, Table1.Surname::text) LIKE '%ar%'
然后我将c#中的结果用作记录列表。而现在我想知道这是如何运作性能明智的。
仅仅迭代列表中的所有记录并选择正确的记录会不会更好?什么会使上述陈述表现更差或更好?很多记录?他们的种类?或者这些选项中的一个只是更好吗?
每次用#34; LIKE' %%'"是不是很糟糕。 (当没有过滤器时)?
答案 0 :(得分:2)
正如dasblinkenlight指出的那样,也许这不是你真正想要的,因为你最终可能会得到一些结果,这些结果会占据名称的一部分,而一部分来自姓氏作为匹配。如果您想同时过滤名称和姓氏,您可能希望在它们之间包含空格:
select * FROM Table1
WHERE concat(concat(Table1.Name::text, ' '), Table1.Surname::text) LIKE '%ar%'
但是,CONCAT功能不能忽视性能。如果您不介意单独检查姓名和姓氏,这对您来说会更快:
select * FROM Table1
WHERE Table1.Name::text LIKE '%ar%' OR Table1.Surname::text LIKE '%ar%'
当然,获取所有数据并在C#中稍后过滤将总是更慢。
答案 1 :(得分:2)
在大多数情况下,我同意@ armarru的答案,但是,我看到的一个问题是你正在将糟糕的性能负担从客户端转移到数据库。据推测,数据库服务器可以更好地处理这个问题,当然还有将这些结果从服务器传输到应用程序的网络带宽,但无论哪种方式,SOME系统都在评估所有记录和过滤到你想要的那些。
使用%search string%
通配符可以防止使用任何标准索引,因此您正在查看全表扫描。
但有好消息。我认为有两个很棒的扩展可以提供帮助。第一个是citext
,它使您能够在不受性能影响的情况下执行不区分大小写的搜索。加载扩展程序后,您可以使字段数据类型为citext
,而不是text
(或varchar
或其他),并搜索' ar'也将返回' Ar'没有任何令人讨厌的上部或下部功能。我认为即使ilike
也会破坏你的索引。
第二个是pg_trgm
,可以进行完整的通配符搜索。正常的B树索引将支持像%'搜索但不是'%喜欢'或者像%'%搜索。此扩展程序可以启用索引等百分比%'%搜索。这令人兴奋。
以下是这些索引的示例。
CREATE INDEX Table1_ix1 on table1 using gin (Name gin_trgm_ops);
CREATE INDEX Table1_ix2 on table1 using gin (Surname gin_trgm_ops);
现在,如果你实施armarru的解决方案:
select * FROM Table1
WHERE Table1.Name::text LIKE '%ar%' OR Table1.Surname::text LIKE '%ar%'
查询可以使用新索引和位图或条件在没有全表扫描的情况下快速为您带来结果。
除非我们正在谈论大量的数据,否则通过将所有记录拉到客户端并在那里过滤,这将使您可能获得的任何性能相形见绌。
另一个对armarru的答案的正面评论是OR
解决方案是首选,因为如果名称导致真实条件,它将执行短路并且不会费心评估姓氏。