【发布时间】:2016-06-23 04:50:31
【问题描述】:
使用 Postgres 9.5,我有一个表 addresses。
CREATE TABLE addresses (
id integer PRIMARY KEY,
address text
);
在该表中,我有 750 万行。示例:
1, "1600 Pennsylvania Avenue NW, Washington, DC, 20500"
我在我的应用程序中使用此表进行自动建议搜索,因此我需要使用这种类型的查询:
SELECT * FROM addresses WHERE address LIKE '123 Main St%';
我创建了这个索引:
CREATE INDEX address_idx ON addresses (address);
但问题是它需要大约 1 秒,这太慢了。
这是查询计划:
EXPLAIN SELECT * FROM addresses WHERE address LIKE '123 Main St%';
----
Seq Scan on addresses (cost=0.00..161309.76 rows=740 width=41)
Filter: (address ~~ '123 Main St%'::text)
我尝试创建几种类型的 gin 索引,但它们要么没有效果,要么使查询变慢。我不确定我是否正确使用它们。
关于如何创建针对此类查询优化的索引有什么想法吗?
编辑
目前发现的最佳解决方案是使用文本范围扫描:
SELECT *
FROM addresses
WHERE address >= '123 Main St' AND
address <= concat('123 Main St', 'z');
【问题讨论】:
-
这总是前缀搜索吗?然后你可以试试 WHERE address BETWEEN '123 Main St' AND '123 Main Su'。这应该会对索引产生范围扫描。
-
索引对于这个查询应该可以正常工作。也许与文本类型不兼容,以某种方式阻止了索引的使用。
-
@Thilo 谢谢!使用 BETWEEN 产生与 LIKE 查询相同的结果,并将时间减少到 13 毫秒。要回答您的问题,是的,这将始终是前缀搜索。我唯一不喜欢这种方法的是我必须想出字母表中的下一个字母或下一个数字,而不是使用通配符。有没有其他方法可以生成范围扫描而无需编写那种逻辑?
-
理想情况下,查询规划器应该检测到前缀搜索并将其转换为 BETWEEN 查询。即使没有,最坏的情况也应该是索引扫描(而不是表扫描)——在这种情况下,这不会更快。
标签: sql postgresql indexing sql-like gwt-gin