-1

我在两张大桌子上执行一个简单的自然连接。

  • 多边形包含 68,000 行 (45 MB)
  • roadhydro 包含大约 200 万行(210 MB)。

这是否意味着数据库引擎在内部执行自然连接时会生成 68,000*200 万行的数据集?如果是这样,那么所需的内存量必须是 45*210 MB,这比我的系统只有 1.5 GB 大得多。

当我执行此查询时,5 分钟后我的系统崩溃(突然关闭)。它不能处理数据库上 250 MB 的数据吗?那么数据库有什么用呢?

"I am modifying the above Question to clear the doubts of readers. 29-02-2012 today."

似乎我的许多朋友都感到困惑,因为我在上面的问题中提到了“自然加入”这个词。我使用的真正空间查询是:

select p.OID , r.OID
    from poygons as p , roadshydro as r
                Where st_intersects(p.the_geom , r.the_geom) ;

其中 polygons & roadhydro 表每个都有两个字段: OID , the_geom 。显然,它是两个表的叉积,而不是某个公共键上的自然连接。

当我执行上述查询时,我监控主内存消耗。它什么也没发生。没有任何内存消耗,我也没有得到任何输出,但 CPU 使用率几乎是 100%。似乎数据库根本没有进行任何计算。但是,如果我从查询中删除 where 子句,主内存消耗逐渐变得过高(5-6 分钟后)导致系统崩溃和机器突然关闭。这就是我正在经历的。删除 where 子句有什么特别之处?为什么 postgres 无法执行查询!对这种行为感到惊讶。

4

4 回答 4

1

使用该NATURAL JOIN构造几乎没有意义。话虽如此,如果连接匹配两个表中的每条记录,您描述的查询只会产生两个表的乘积。

仅当两个表中都有一个字段名称相同且每条记录的值都相同时,才会发生这种情况 - 这是极不可能的,但在逻辑上并非不可能,或者如果 2 个表中没有与名称匹配的字段。

如果我是你,我会放弃NATURAL JOIN使用 plain JOIN,指定你想要匹配的字段。

如果这解决了崩溃,那么一切都很好,但如果确实如此,我会感到惊讶。

于 2011-10-12T08:03:46.717 回答
0

由于我对这篇文章的评论受到批评,我准备了一个例子来说明我对这个主题的看法。

以下 Oracle 脚本说明了我认为使用该NATURAL JOIN构造所固有的危险。我承认这是一个人为的例子,但为了防御性发展,我相信我的立场是正确的。

DROP TABLE TABLE1;
DROP TABLE TABLE2;

CREATE TABLE TABLE1 (
FIELD1   VARCHAR2(10),
FIELD2   VARCHAR2(10),
DESCR_T1 VARCHAR2(20)
);

CREATE TABLE TABLE2 (
FIELD1   VARCHAR2(10),
FIELD2   VARCHAR2(10),
DESCR_T2 VARCHAR2(20)
);

INSERT INTO TABLE1 VALUES('AAA','AAA',    'AAA_AAA_T1'   );
INSERT INTO TABLE1 VALUES('BBB','BBB',    'BBB_BBB_T1'   );
INSERT INTO TABLE1 VALUES('CCC','T1_CCC', 'CCC_T1_CCC_T1');
INSERT INTO TABLE1 VALUES('DDD','T1_DDD', 'DDD_T1_DDD_T1');
INSERT INTO TABLE1 VALUES('EEE',NULL    , 'EEE_NULL_T1'  );

INSERT INTO TABLE2 VALUES('AAA','AAA',    'AAA_AAA_T2'   );
INSERT INTO TABLE2 VALUES('BBB','BBB',    'BBB_BBB_T2'   );
INSERT INTO TABLE2 VALUES('CCC','T2_CCC', 'CCC_T1_CCC_T2');
INSERT INTO TABLE2 VALUES('DDD','T2_DDD', 'DDD_T1_DDD_T2');
INSERT INTO TABLE2 VALUES('EEE',NULL    , 'EEE_NULL_T2'  );

COMMIT;

-- try the following queries and review the results

SELECT 
  FIELD1, DESCR_T1, DESCR_T2 
FROM 
  TABLE1 NATURAL JOIN TABLE2;

SELECT 
  * 
FROM 
  TABLE1 NATURAL JOIN TABLE2;

SELECT 
  TABLE1.FIELD1, TABLE1.DESCR_T1, TABLE2.DESCR_T2 
FROM 
  TABLE1 JOIN 
    TABLE2 ON 
      TABLE2.FIELD1 = TABLE1.FIELD1 AND 
      TABLE2.FIELD2 = TABLE1.FIELD2;

SELECT * FROM 
  TABLE1 NATURAL JOIN TABLE2;

-- Issue the following statement then retry the previous 3 statements.
-- The 'NJs' silently change behaviour and produce radically different results
-- whereas the third requires hands-on attention.  I believe this third behaviour
-- is desirable.  (You could equally drop the column TABLE2.FIELD2 as dportas 
-- has suggested

-- ALTER TABLE TABLE2 RENAME COLUMN FIELD2 TO T2_FIELD2;
于 2011-11-16T13:56:56.933 回答
0

扩展 Hugh 的示例数据,这里是两个 NATURAL JOIN 查询的示例。希望可以从 Hugh 描述的问题中看出这些是“安全的”,并且 NJ 版本实际上比 INNER JOIN 版本更简洁(并且在我看来更具可读性)。

SELECT *
FROM 
(SELECT FIELD1, DESCR_T1 FROM TABLE1) T1
NATURAL JOIN
(SELECT FIELD1, DESCR_T2 FROM TABLE2) T2;

SELECT * 
FROM 
(SELECT FIELD1, FIELD2, DESCR_T1 FROM TABLE1) T1
NATURAL JOIN
(SELECT FIELD1, FIELD2, DESCR_T2 FROM TABLE2) T2;

除非您编写草率的代码,否则休所说的问题不存在。如果您确实编写了草率的代码,那么 INNER JOIN 也是“不安全的”。这种交流可能确实说明了自然连接并不总是很好理解。这可能是一些人无理怀疑他们的原因。

于 2011-11-16T19:33:59.603 回答
0

这实际上取决于许多不同的因素,但最重要的是您使用的 DBMS 及其配置。

但要消除最大的误解:DBMS 不必将所有行都保存在内存中:它可以写入临时表(在硬盘上)并为您提供结果......慢慢......所以如果它崩溃了,这是不正常的。

再说一次,你为什么要问 68k*2M 行?那是 136,000,000,000 行!你确定你不想直接加入某个键吗?

于 2011-10-12T06:34:26.977 回答