Postgresql 如何让Postgres在订购后计算列?

Postgresql 如何让Postgres在订购后计算列?,postgresql,query-optimization,Postgresql,Query Optimization,我有一些大型sql查询,在SELECT块中有许多计算列。此外,还可以按其中一个计算列进行排序,并且仅限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()

我有一些大型sql查询,在SELECT块中有许多计算列。此外,还可以按其中一个计算列进行排序,并且仅限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;
由于索引的原因,它将非常快。如果我们增加col1的订单,速度仍然会很快。但如果我们使用max_val1的ORDER,则需要大约2秒钟。 如果我们使用“ORDER BY max_val1”对查询运行解释分析,我们将看到以下行:

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在执行排序和限制后计算列?

限制整个查询的输出,而不是主查询中的子查询的输出。如果只希望最大值为100行,则需要首先选择它们,然后对该子集应用最大值:

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;

请注意,没有ORDER BY的限制实际上没有意义。关系数据库中的行没有顺序。因此,除非指定排序顺序,否则不存在表中的前100行

无关,但是:您的DO块可以替换为简单的INSERT语句:例如:INSERT into test_maincol1从generate_series 1100000中选择truncrandom*1000;谢谢,我不知道生成_系列函数。我会记住:是的,你是对的。我忘记了在子查询中使用ORDERBY和LIMIT的可能性。然后我可以将我的示例中的查询重写为:选择t.*,选择。。。最大值2从选择列1,选择。。。测试主订单的最大值为100 t;