【问题标题】:join tables on like with index用索引连接表
【发布时间】:2015-10-20 01:42:41
【问题描述】:

我有一个 URL 表(域和页面)

URLs
-----
url_id

url

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

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

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

https://stackoverflow.com/question/230479

https://stackoverflow.com/question/395872364

URL 表相当大,1000 万+,而且还会增长

我要测试的域名列表会在 1-10k 之间变化

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

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

我已经为 URLs.url 和 tmp_table_domain.domain 编制了索引,并认为索引将起作用,因为通配符在右侧。

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

如果有帮助,我的 postgres 是 9.1。如果升级可以解决这个问题,那很好,唯一没有升级的原因并不是我所知道的任何原因

编辑_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;博士

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

【问题讨论】:

  • 但为什么是临时表?请务必发布您的解释输出
  • 因为我真的不知道我在做什么和在各种事情上进行黑客攻击,这是目前我拥有的最好的 :-) 在它只是一个大的 WHERE url LIKE 'domain1.com%' 之前'domain2.com%' 或 ...'domain9999.com%'
  • 您的 tmp 域表的内容来自哪里?
  • 它通过消息队列来自外部进程。基本上我有一个接收列表的python函数,我想找到所有匹配它的现有项目
  • 添加了解释分析输出。实际查询与最初所说的简化版本有点不同,唯一的主要区别是 task_items 是 URLs 表

标签: postgresql postgresql-9.1


【解决方案1】:

几个月前,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:// url。如果您不希望这样,那么也加入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,这样你就可以放弃演员表了。

【讨论】:

  • 绝对看起来值得关注,但最终从源代码构建以及我可能需要匹配部分非 url 例如 1234_abcd 需要匹配 1234 意味着没有进一步检查这个
猜你喜欢
  • 2013-03-29
  • 2017-11-25
  • 1970-01-01
  • 2016-03-10
  • 2011-09-02
  • 1970-01-01
  • 2019-04-03
  • 2012-10-03
  • 2013-12-01
相关资源
最近更新 更多