像索引一样连接表

时间:2015-10-20 01:42:42

标签: postgresql postgresql-9.1

我有一个网址表(域名和网页)

URLs
-----
url_id

url

我有一个域名列表,我想看看它是否包含在URL表中。

所以,如果我的列表中有域名: http://stackoverflow.com

我希望它匹配以下URL:url记录:

https://stackoverflow.com/question/230479

https://stackoverflow.com/question/395872364

URL表非常大,1000万+并且会增长

我想测试的域名列表将在1-10k

之间变化

目前我正在创建域列表的临时表,然后加入URL表以查找匹配的所有URL

SELECT * from URLs
JOIN tmp_table_domains on tmp_table_domain.domain like URLs.url || '%'

我已经将URL.url和tmp_table_domain.domain编入索引,并认为索引将在外卡的右侧工作。

但是,EXPLAIN ANALYZE不显示正在使用的任何索引。一篇帖子中提到postgres 8.x不能像索引一样加入,但是我找不到任何其他方法来支持这个或替代方案,或者它是否适用于更新的版本

如果有帮助,我的帖子是9.1。如果升级会解决这个问题,那很好,只有没有升级的理由没有任何理由让我知道

Edit_1  这是第一个已经开展工作的数据库项目,我正在学习这一切

我不介意删除所有上述内容并使用更好的方法,无论是临时表/数组/更好的查询

edit_2

 GroupAggregate  (cost=1429152.90..1435118.48 rows=340890 width=44) (actual time=157905.450..157905.609 rows=27 loops=1)
   ->  Sort  (cost=1429152.90..1430005.13 rows=340890 width=44) (actual time=157905.425..157905.451 rows=29 loops=1)
         Sort Key: task_items.task_item
         Sort Method: quicksort  Memory: 29kB
         ->  Nested Loop  (cost=14210.95..1387337.41 rows=340890 width=44) (actual time=18216.187..157905.055 rows=29 loops=1)
               Join Filter: ((task_items.task_item)::text ~~ ((tmp_domains.domain)::text || '%'::text))
               ->  Hash Join  (cost=14210.95..194126.53 rows=14066 width=44) (actual time=452.262..7953.639 rows=13737 loops=1)
                     Hash Cond: (task_items.task_id = tasks.task_id)
                     ->  Seq Scan on task_items  (cost=0.00..170062.71 rows=2589924 width=48) (actual time=0.019..4480.360 rows=2575206 loops=1)
                           Filter: (task_item_status_id = 2)
                     ->  Hash  (cost=14205.68..14205.68 rows=421 width=4) (actual time=440.409..440.409 rows=171 loops=1)
                           Buckets: 1024  Batches: 1  Memory Usage: 7kB
                           ->  Seq Scan on tasks  (cost=0.00..14205.68 rows=421 width=4) (actual time=101.491..439.821 rows=171 loops=1)
                                 Filter: ((account_detail_id = 695) AND (base_action_type_id <> ALL ('{1,3,4}'::integer[])))
               ->  Materialize  (cost=0.00..109.70 rows=4847 width=32) (actual time=0.002..4.924 rows=4536 loops=13737)
                     ->  Seq Scan on tmp_domains  (cost=0.00..85.47 rows=4847 width=32) (actual time=0.010..5.851 rows=4536 loops=1)
 Total runtime: 157907.403 ms

实际查询与上面的简化说明略有不同。

task_items的行数不到700万 并且tmp_domains有4,500

TL;博士

总结一下。将字符串列表部分匹配到列的最佳方法是什么

1 个答案:

答案 0 :(得分:0)

几个月前,Peter Eisentraut发表了pguri extension,这可以大大简化你的工作。它目前只是源代码,因此您必须构建库代码,这在任何Linux机器上都非常容易,然后将文件放在PG安装目录中,最后放在数据库中CREATE EXTENSION。之后,您可以执行简单的查询,例如:

SELECT *
FROM urls
JOIN tmp_table_domains d ON uri_host(d.domain::uri) = uri_host(urls.url::uri);

请注意,这也会在不同的方案之间匹配,因此http://域将匹配相应的https://网址。如果您不想这样做,那么还要加入uri_scheme()域名和网址。

索引将适用于扩展函数返回的text数据类型。如果您的数据库使用UTF-8编码,您应该像这样创建索引:

CREATE INDEX url_index ON urls (uri_host(url::uri) text_pattern_ops);

然后还有你的域名表。

你可以ALTER TABLE urls ALTER COLUMN url SET DATA TYPE uri这样你可以放弃演员。