postgresql 大型数据集复杂连接和聚集的查询优化

ycggw6v2  于 12个月前  发布在  PostgreSQL
关注(0)|答案(2)|浏览(165)
Table A: (columns: id (integer), name (varchar), ...)
Table B: (columns: id (integer), a_id (integer), value (numeric), ...)
Table C: (columns: id (integer), a_id (integer), b_id (integer), date (date), ...)
SELECT A.name, SUM(B.value) AS total_value,
    COUNT(DISTINCT C.date) AS distinct_dates
FROM A
JOIN B ON A.id = B.a_id
JOIN C ON B.id = C.b_id
WHERE C.date BETWEEN '2022-01-01' AND '2022-12-31'
GROUP BY A.name
ORDER BY total_value DESC;

即使只限于特定的日期范围,查询的执行也需要相当长的时间。相关列上有索引。
表A大约有1000万行。
表B大约有2000万行。
表C大约有5000万行。
查询执行时间随着日期范围的增大而呈指数级增长。
哪些特定的索引、查询重写或配置更改可以缩短执行时间?
在大型数据集上处理如此复杂的连接和聚合操作的替代方法是什么?

dsf9zpds

dsf9zpds1#

在不知道实际数据集和数据库配置的情况下很难说。一些一般性的提示是:

  • 确保你有正确的索引:索引可以通过减少要扫描的数据数量来提高查询性能。在您的示例中,应该对连接条件、筛选器和order by子句中使用的所有列都建立索引。(A.idB.a_idB.idC.b_idC.date)。
  • 使用EXPLAIN分析您的查询:它可以帮助您了解查询将如何执行,以便您可以识别潜在的瓶颈。
  • 尝试重写查询:有时它有助于提高性能。Tou可以尝试子查询或CTE将查询分解为更小的部分。
  • 考虑对数据进行分区:它还可以帮助减少要扫描的数据的数量。但这取决于您的数据是否可以拆分为更易于管理的块。
m4pnthwp

m4pnthwp2#

相关列上有索引
为了让这个查询快速运行,你应该在C的date列和它的a_id上有一个索引,这样就可以快速地从WHERE子句到达第一个连接。

create index idx_c on c (date) include (b_id);

你有这个索引吗?
如果这仍然太慢,您可能需要考虑在其他表上提供覆盖索引:

create unique index idx_b on b (id) include (a_id, value);

create unique index idx_a on a (id) include (name);

最后,这一切仍然取决于您提供的日期范围以及DBMS基于此做出的决定。如果你的日期范围覆盖了C行的90%,那么全tabke扫描可能比使用索引快得多。如果您的日期范围覆盖了C行的1%甚至更少,那么遍历索引将更快。我们不知道索引变得更好的阈值,但DBMS将尽最大努力做出最佳决策。
由于表A实际上不是聚合的一部分,因此使其对DBMS明显可见可能会有所帮助。理想情况下,优化器应该看到这是同一个查询,并提出相同的执行计划,但优化器并不完美,因此提示可能会不时有所帮助。

SELECT a.name, bc.total_value, bc.distinct_dates
FROM 
(
  SELECT
    a_id,
    SUM(b.value) AS total_value,
    COUNT(DISTINCT C.date) AS distinct_dates
  FROM c
  JOIN b ON b.id = c.b_id
  WHERE c.date BETWEEN DATE '2022-01-01' AND DATE '2022-12-31'
  GROUP BY a_id
) bc
JOIN a on ON a.id = bc.a_id
ORDER BY bc.total_value DESC;

相关问题