0

我对具有 33m 行的表的查询存在性能问题。查询应返回 6m 行。我试图在没有任何明显延迟的情况下实现对请求的响应。我的应用程序中的数据流需要它。启动后,数据传输可能需要更长的时间。困难在于查询有排序。因此,我创建了一个索引,其中包含在“order by”语句和“where”子句中使用的字段。

示例喜欢这样:

CREATE TABLE Table1 (
   Id SERIAL PRIMARY KEY,
   Field1 INT NOT NULL,
   Field2 INT NOT NULL,
   Field3 INT NOT NULL,
   Field4 VARCHAR(200) NOT NULL,
   CreateDate TIMESTAMP,
   CloseDate TIMESTAMP NULL
);
CREATE INDEX IX_Table1_SomeIndex ON Table1 (Field2, Field4);

查询喜欢这样:

SELECT * FROM Table1 t
WHERE t.CreateDate >= '2020-01-01' AND t.CreateDate < '2021-01-01'
ORDER BY t.Field2, t.Field4

它导致以下结果:当我添加“LIMIT 1000”时,它会立即返回结果并构建以下计划: 带有“LIMIT”的计划

当我在没有“LIMIT”的情况下运行时,它会“思考”大约一分钟并返回数据大约 16 分钟。它构建了以下计划: 带有“LIMIT”的计划

为什么计划不同?

你能帮我立即制作souliton(没有限制)吗?

谢谢!

4

2 回答 2

0

您将需要使用服务器端光标或类似的东西才能工作。否则,它会在返回任何结果之前运行查询完成。默认情况下没有“流媒体”。你如何做到这一点取决于你的客户,你没有提到。

如果您只是简单地声明一个游标,然后以块的形式获取,那么该设置cursor_tuple_fraction将控制它是选择具有更快启动成本的计划(例如您使用 LIMIT 获得的),还是更快的总体运行成本(就像您没有限制)。

于 2021-01-30T19:16:15.403 回答
0

如果“当我添加 LIMIT 1000 时,它会立即返回结果”并且您想避免延迟,那么我建议您在使用LIMIT 1000. 一个重要的好处是不会有长时间运行的事务。

在循环中多次运行的查询应该返回(field2, field4)从上一次迭代运行的最大值之后开始的记录。

SELECT * 
  FROM table1 t
 WHERE t.CreateDate >= '2020-01-01' AND t.CreateDate < '2021-01-01'
   AND (t.field2, t.field4) > (:last_run_largest_f2_value, :last_run_largest_f4_value) 
 ORDER BY t.field2, t.field4
 LIMIT 1000;

last_run_largest_f2_valuelast_run_largest_f4_value参数。它们的值应来自上一次迭代返回的最后一条记录。
AND (t.field2, t.field4) > (:last_run_largest_f2_value, :last_run_largest_f4_value)在第一次迭代中应省略。

  • 重要限制

OFFSET如果(field2, field4)值是唯一的,这是一种可以正常工作的替代方法

于 2021-01-30T19:07:31.107 回答