我的问题由以下查询表示:
SELECT
b.row_id, b.x, b.y, b.something,
(SELECT a.x FROM my_table a WHERE a.row_id = (b.row_id - 1), a.something != 42 ) AS source_x,
(SELECT a.y FROM my_table a WHERE a.row_id = (b.row_id - 1), a.something != 42 ) AS source_y
FROM
my_table b
我使用相同的子查询语句两次,以获取source_x
和source_y
。
这就是为什么我想知道是否可以仅使用一个子查询来实现它?
因为一旦我对我的真实数据(数百万行)运行此查询,它似乎永远不会完成并花费数小时,如果不是几天(我的连接在结束前挂断)。
我正在使用PostgreSQL 8.4
答案 0 :(得分:8)
我认为你可以使用这种方法:
SELECT b.row_id
, b.x
, b.y
, b.something
, a.x
, a.y
FROM my_table b
left join my_table a on a.row_id = (b.row_id - 1)
and a.something != 42
答案 1 :(得分:3)
@DavidEG发布了查询的最佳语法。
但是,您的问题绝对不仅仅是查询技术。 JOIN
而不是两个子查询可以将事物加速到最多两倍。很可能更少。这并不能解释“小时”。即使有数百万行,一个体面设置的Postgres也应该在几秒钟内完成简单的查询,而不是几小时。
首先突出的是查询中的语法错误:
... WHERE a.row_id = (b.row_id - 1), a.something != 42
此处需要 AND
或OR
,而不是逗号。
接下来要检查的是索引。如果row_id
不是主键,则可能没有索引。为了获得此特定查询的最佳效果,请在(row_id, something)
上创建multi-column index,如下所示:
CREATE INDEX my_table_row_id_something_idx ON my_table (row_id, something)
过滤器每次something != 42
时都会排除相同值,您也可以使用partial index来提高速度:
CREATE INDEX my_table_row_id_something_idx ON my_table (row_id)
WHERE something != 42
如果42
是公共值或 something
是一个更大的列而不仅仅是一个整数,那么这只会产生重大影响。 (由于数据对齐,具有两个integer
列的索引通常在磁盘上占用与仅有一个索引相同的大小。请参阅:
当表现出现问题时,check your settings始终是个好主意。 Postgres中的标准设置在许多发行版中使用最少的资源,而不是处理“数百万行”。
根据您的Postgres的实际版本, upgrade to a current version (撰写本文时为9.1)可能会有很大帮助。
最终,hardware也是一个因素。调整和优化只能让你到目前为止。
答案 2 :(得分:0)
老式语法:
SELECT
b.row_id, b.x, b.y, b.something
, a.x AS source_x
, a.y AS source
FROM my_table b
,my_table a
WHERE a.row_id = b.row_id - 1
AND a.something != 42
;
加入-语法:
SELECT
b.row_id, b.x, b.y, b.something
, a.x AS source_x
, a.y AS source
FROM my_table b
JOIN my_table a
ON (a.row_id = b.row_id - 1)
WHERE a.something != 42
;
答案 3 :(得分:0)
SELECT b.row_id, b.x, b.y, b.something, a.x, a.y
FROM my_table b
LEFT JOIN (
SELECT row_id + 1, x, y
FROM my_table
WHERE something != 42
) AS a ON a.row_id = b.row_id;
答案 4 :(得分:0)
Postgres:
SELECT
b.row_id, b.x, b.y, b.something,
source_x,
source_y
FROM
my_table b,
LATERAL(SELECT a.x AS source_x, a.y AS source_y FROM my_table a WHERE a.row_id = (b.row_id - 1), a.something != 42 )
MSSQL
SELECT
b.row_id, b.x, b.y, b.something,
source_x,
source_y
FROM
my_table b
OUTER APPLY(SELECT a.x AS source_x, a.y AS source_y FROM my_table a WHERE a.row_id = (b.row_id - 1), a.something != 42 )