Alf*_*tig 3 sql postgresql indexing unaccent openstreetmap
我想从导入PostgreSQL 9.3.5的OpenStreetMap数据库中检索具有给定名称的方法,操作系统是Win7 64位.为了有点容错,我使用了Postgres的unaccent扩展.
我的查询如下:
SELECT * FROM germany.ways
WHERE lower(tags->'name') like lower(unaccent('unaccent','Weststrasse'))
Run Code Online (Sandbox Code Playgroud)
查询计划:
Seq Scan on ways (cost=0.00..2958579.31 rows=122 width=465)
Filter: (lower((tags -> 'name'::text)) ~~ lower(unaccent('unaccent'::regdictionary, 'Weststrasse'::text)))
Run Code Online (Sandbox Code Playgroud)
奇怪的是,此查询使用顺序扫描方式,尽管索引存在于lower(tags->'name'):
CREATE INDEX ways_tags_name ON germany.ways (lower(tags -> 'name'));
Run Code Online (Sandbox Code Playgroud)
一旦我从查询中删除unaccent,Postgres就会使用索引:
SELECT * FROM germany.ways
WHERE lower(tags->'name') like lower('Weststrasse')
Run Code Online (Sandbox Code Playgroud)
查询计划:
Index Scan using ways_tags_name on ways (cost=0.57..495.43 rows=122 width=465)
Index Cond: (lower((tags -> 'name'::text)) = 'weststrasse'::text)
Filter: (lower((tags -> 'name'::text)) ~~ 'weststrasse'::text)
Run Code Online (Sandbox Code Playgroud)
为什么无法防止Postgres使用索引?在我看来,这没有意义,因为在执行实际查询之前,应该已经完全知道unaccent(变音符号删除等)的结果.所以Postgres应该能够使用索引.使用unaccent时如何避免seq扫描?
Erw*_*ter 13
unaccent()澄清当前接受的错误答案中的错误信息:
表达式索引仅允许IMMUTABLE函数(出于显而易见的原因)并且unaccent()仅是STABLE.您在评论中建议的解决方案也存在问题.详细解释和妥善的解决办法 为:
根据其内容,tags->name添加unaccent()到表达式索引可能很有用,但这与索引未被使用的问题正交:
LIKE您的查询中的运算符是巧妙的错误(最有可能).您不希望将"Weststrasse"解释为搜索模式,您希望按原样匹配(规范化的)字符串.替换为=运算符,您将看到一个(位图)索引扫描与您当前的索引,无论函数的波动性如何unaccent():
SELECT * FROM germany.ways
WHERE lower(tags->'name') = lower(unaccent('unaccent','Weststrasse'))Run Code Online (Sandbox Code Playgroud)
右操作数LIKE是一种模式.Postgres不能使用普通的btree索引进行模式匹配(例外情况适用).LIKE可以使用btree索引上的相等性检查来优化使用普通字符串作为模式(无特殊字符)的A. 但是如果字符串中有特殊字符,则该索引已经输出.
如果IMMUTABLE右边有一个函数LIKE,则可以立即对其进行评估,并且仍然可以进行所述优化.关于函数波动率类别的每个文档:
IMMUTABLE...
此类别允许优化器在查询使用常量参数调用函数时预先评估函数.
功能波动性较小(STABLE或VOLATILE)时,这是不可能的.这就是为什么你的伪造"解决方案" IMMUTABLE unaccent()似乎有效,但它确实在口红上涂上了口红.
重申:
LIKE和模式,请使用trigram索引.LIKE和模式,请使用相等运算符=