我在SELECT
块中有很多计算列的大sql查询。此外,还有一个计算列的排序,并且只限制了100行。但是postgres会计算每一行的所有列,而不仅仅是100行。
让我解释一下。
让我们创建一些测试表:
CREATE TABLE test_main(col1 INTEGER);
并填写一些随机数据:
DO
$do$
BEGIN
FOR r IN 1..100000 LOOP
INSERT INTO test_main(col1) VALUES (trunc(random()*1000));
END LOOP;
END
$do$;
然后创建一些额外的表:
CREATE TABLE test_main_agg1(
col1 INTEGER,
val INTEGER
);
CREATE TABLE test_main_agg2(
col1 INTEGER,
val INTEGER
);
并填写它:
DO
$do$
DECLARE
r test_main%rowtype;
BEGIN
FOR r IN SELECT * FROM test_main LOOP
FOR i IN 1..5 LOOP
INSERT INTO test_main_agg1(col1, val) VALUES (r.col1, trunc(random()*1000));
INSERT INTO test_main_agg2(col1, val) VALUES (r.col1, trunc(random()*1000));
END LOOP;
END LOOP;
END
$do$;
当然,创建一些索引:
CREATE INDEX test_main_indx ON test_main(col1);
CREATE INDEX test_main_agg1_val_indx ON test_main_agg1(col1,val);
CREATE INDEX test_main_agg2_val_indx ON test_main_agg2(col1,val);
现在,如果我们执行此查询:
SELECT col1,
(SELECT MAX(val) FROM test_main_agg1 g WHERE g.col1=m.col1) max_val1,
(SELECT MAX(val) FROM test_main_agg2 g WHERE g.col1=m.col1) max_val2
FROM test_main m
LIMIT 100;
由于索引,它会非常快。如果我们添加ORDER BY col1
,它仍然会很快。但是如果我们使用ORDER BY max_val1
,那么大约需要2秒钟。
如果我们使用`ORDER BY max_val1对查询运行EXPLAIN ANALYZE
,我们将看到以下行:
SubPlan 4
-> Result (cost=4.06..4.07 rows=1 width=0) (actual time=0.011..0.011 rows=1 loops=100000)
InitPlan 3 (returns $3)
-> Limit (cost=0.42..4.06 rows=1 width=4) (actual time=0.010..0.010 rows=1 loops=100000)
-> Index Only Scan Backward using test_main_agg2_val_indx on test_main_agg2 g_1 (cost=0.42..1818.25 rows=500 width=4) (actual time=0.010..0.010 rows=1 loops=100000)
Index Cond: ((col1 = m.col1) AND (val IS NOT NULL))
Heap Fetches: 100000
这意味着,postgres为100000行计算max_val2
,但不仅仅计算100行。我理解为什么postgres需要计算max_val1
,而不是max_val2
。
在执行排序和限制后,可能会有一些提示或类似的东西告诉postgres计算列?
答案 0 :(得分:1)
LIMIT
限制整个查询的输出,而不是主查询中的子查询。如果您只想要最多100行,则需要先选择它们,然后在该子集上应用max():
SELECT col1,
(SELECT MAX(val) FROM test_main_agg1 g WHERE g.col1=m.col1) max_val1,
(SELECT MAX(val) FROM test_main_agg2 g WHERE g.col1=m.col1) max_val2
FROM (
select val, col1
from test_main
LIMIT 100
) m;
请注意,limit
没有和ORDER BY
并不合理。关系数据库中的行没有顺序。因此,除非指定排序顺序,否则表中没有“前100行”。