【发布时间】:2018-09-22 19:46:31
【问题描述】:
我正在 PgSQL 中使用类似的查询执行全文搜索(目的是根据搜索到的城市名称返回地理编码城市列表):
SELECT *
FROM cities
WHERE city_tsvector @@ to_tsquery('Paris')
AND postcode LIKE '75%'
这个查询在我的数据库上执行得非常快(city 表中有 425626 个条目):大约 100 毫秒。到目前为止,一切顺利。
现在,我必须同时搜索 400 个城市。
400 x 100ms = 40 秒,这对我的用户来说太长了。
我正在尝试编写一个查询,以一次性执行此搜索。一个细节:我必须搜索的城市没有存储在数据库中。
所以我写了这样的查询:
SELECT DISTINCT ON (myid) *
FROM unnest(
array[19977,19978,19979, (and so on)]::int[],
array['SAULXURES','ARGENTEUIL','OBERHOFFEN&SUR&MODER', (and so on)]::text[],
array['67','95','67','44', (and so on))]::text[]
) AS t(myid, cityname,mypostcode)
LEFT JOIN cities gc2 ON gc2.city_tsvector @@ to_tsquery(cityname) AND gc2.postcode LIKE CONCAT(mypostcode,'%')
ORDER BY myid
;
结果是灾难性的:对于相同的搜索,查询的速度要慢 4 倍!
是否可以执行这种查询以减少执行时间?
谢谢
编辑
这是表城市结构(425626 行):
使用@The-Impaler 回答编辑:
- 选项 #1:邮政编码前两个字符的索引
查询需要 11 秒
详细解释:
唯一(成本=71133.21..71138.53 行=100 宽度=40) 输出:t.myid, (st_astext(gc2.gps_coordinates)) -> 排序(成本=71133.21..71135.87 行=1064 宽度=40) 输出:t.myid, (st_astext(gc2.gps_coordinates)) 排序键:t.myid -> 哈希右连接(成本=2.26..71079.72 行=1064 宽度=40) 输出:t.myid, st_astext(gc2.gps_coordinates) 哈希条件: (left((gc2.postcode)::text, 2) = t.mypostcode) 加入过滤器:(gc2.city_tsvector @@ to_tsquery(t.cityname)) -> public.geo_cities gc2 上的 Seq 扫描(成本=0.00..13083.26 行=425626 宽度=69) 输出:gc2.id, gc2.country_code, gc2.city, gc2.postcode, gc2.gps_coordinates, gc2.administrative_level_1_name, gc2.administrative_level_1_code, gc2.administrative_level_2_name, gc2.administrative_level_2_code, gc2.administrative_level_ (...) -> 哈希(成本=1.01..1.01 行=100 宽度=72) 输出:t.myid、t.cityname、t.mypostcode -> t 上的函数扫描(成本=0.01..1.01 行=100 宽度=72) 输出:t.myid、t.cityname、t.mypostcode 函数调用:UNNEST(“{289148879225,289148879225,289148879225,289148879225,289148879225,289148879225,289148879225,289148879225,289148879225,289148879225,289148879225,289148879225,289148879225,289148879225,289148879225,28914887922(...)- 选项 #2:按邮政编码过滤时使用 = 而不是 LIKE
查询需要 12 秒
详细解释:
唯一(成本=71665.25..71670.57 行=100 宽度=40) 输出:t.myid, (st_astext(gc2.gps_coordinates)) -> 排序(成本=71665.25..71667.91 行=1064 宽度=40) 输出:t.myid, (st_astext(gc2.gps_coordinates)) 排序键:t.myid -> 哈希右连接(成本=2.26..71611.75 行=1064 宽度=40) 输出:t.myid, st_astext(gc2.gps_coordinates) 哈希条件:((substring((gc2.postcode)::text, 1, 2))::text = t.mypostcode) 加入过滤器:(gc2.city_tsvector @@ to_tsquery(t.cityname)) -> public.geo_cities gc2 上的 Seq 扫描(成本=0.00..13083.26 行=425626 宽度=69) 输出:gc2.id, gc2.country_code, gc2.city, gc2.postcode, gc2.gps_coordinates, gc2.administrative_level_1_name, gc2.administrative_level_1_code, gc2.administrative_level_2_name, gc2.administrative_level_2_code, gc2.administrative_level_ (...) -> 哈希(成本=1.01..1.01 行=100 宽度=72) 输出:t.myid、t.cityname、t.mypostcode -> t 上的函数扫描(成本=0.01..1.01 行=100 宽度=72) 输出:t.myid、t.cityname、t.mypostcode 函数调用:UNNEST(“{289148879225,289148879225,289148879225,289148879225,289148879225,289148879225,289148879225,289148879225,289148879225,289148879225,289148879225,289148879225,289148879225,289148879225,289148879225,28914887922(...)【问题讨论】:
-
您是否只需要从城市表中获取“地理编码”列还是还需要其他一些列?
-
你可以修改数据库吗?我不确定您有多少不同的邮政编码以及它们的格式,但也许在邮政编码的两个首字母上有一个索引并对其进行过滤会有所帮助
-
我只需要 myid 和地理编码列
-
@jmriego 在邮政编码字段上有一个索引,查询时间减少了 10 秒,但仍然比逐行执行要慢得多
-
对不起@frinux 我的意思是在索引的前两个字符上有一个索引。 CREATE INDEX start_postcode_cities ON 城市(左(邮编,2));然后过滤 where left(postcode,2) IN ('11', 22'...
标签: sql postgresql performance join full-text-search