sql - 理解 postgreSQL 中的 HashJoin

标签 sql postgresql join hash

让我们考虑以下查询:

EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM foo JOIN bar ON foo.c1=bar.c1;

在哪里

CREATE TABLE foo
(
  c1 integer,
  c2 text
)

CREATE TABLE bar
(
  c1 integer,
  c2 boolean
)

如本 article 中所述

PostgreSQL does a sequential scan of table bar, and computes the hash for each of its rows. Then, it does a sequential scan of foo, and for each row, computes the hash of the row and compares it to the bar hashed table. If it matches, the row will be put in the resulting set. If it doesn't match, the row is skipped.

计划如下:

Hash Join  (cost=13463.00..49297.00 rows=500000 width=42) (actual time=95.634..1001.306 rows=500000 loops=1)
  Hash Cond: (foo.c1 = bar.c1)
  Buffers: shared hit=3850 read=6697
  ->  Seq Scan on foo  (cost=0.00..18334.00 rows=1000000 width=37) (actual time=0.026..135.609 rows=1000000 loops=1)
        Buffers: shared hit=1637 read=6697
  ->  Hash  (cost=7213.00..7213.00 rows=500000 width=5) (actual time=95.478..95.478 rows=500000 loops=1)
        Buckets: 65536  Batches: 1  Memory Usage: 18067kB
        Buffers: shared hit=2213
        ->  Seq Scan on bar  (cost=0.00..7213.00 rows=500000 width=5) (actual time=0.004..37.040 rows=500000 loops=1)
              Buffers: shared hit=2213
Total runtime: 1017.572 ms

我无法理解的是如何确定该行是否应该在结果集中。哈希值相等的事实并不意味着行满足谓词 foo.c1=bar.c1

问题: 那么,在比较哈希之后,我们应该检查谓词是否满足?另外,是否每个桶都包含具有相同散列的行?

最佳答案

  1. 那么,在比较哈希之后,我们应该检查谓词是否满足?

是的。

哈希连接使用连接属性作为哈希键。当两行的散列函数值相等时,我们必须 (a) 检查连接属性实际上是否相等,以及 (b) 检查是否也满足其他连接条件。

在您的示例中,连接属性是 foo.c1bar.c1,并且没有其他连接条件。

更复杂的示例:SELECT * FROM foo JOIN bar ON foo.c1 = bar.c1 AND foo.c1 > bar.c1;。在这种情况下,我们仍然可以在 = 运算符上使用散列连接,但还必须检查 foo.c1 > bar.c1

如果您对细节感兴趣,请查看源代码(以 nodeHashjoin.c 开头)。


  1. 每个桶是否必须包含具有相同散列的行?

根据定义它是正确的,不是吗?哈希函数将键映射到哈希表中的索引,即。 e.到桶数字。

但严格来说,不是具有相同散列的行,而是连接具有相同散列的属性

关于sql - 理解 postgreSQL 中的 HashJoin,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33018683/

相关文章:

SQL - 提取两个字符之间的子字符串

node.js - 嵌套对象查询到 Prisma 中的单个数组

postgresql - 在没有 Postgis 功能的情况下转储或恢复 Postgresql 数据库

mysql - SQL 使用子查询而不是一对多的连接

mysql - 如何避免 LEFT JOIN 查询中的重复记录?

sql - 递归 CTE 检查记录是否存在于任何级别,然后获取所有子级(文件夹结构)

php mysql_query() 返回 false

java - Java 中关闭数据库连接

postgresql - 在官方 Postgres docker 镜像中记录所有查询

MySQL JOIN 在 1 个大表和多个小表上的性能