Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
优化连接->;PostgreSQL中的分组查询:所有索引都已存在_Sql_Postgresql_Join_Group By_Query Optimization - Fatal编程技术网

优化连接->;PostgreSQL中的分组查询:所有索引都已存在

优化连接->;PostgreSQL中的分组查询:所有索引都已存在,sql,postgresql,join,group-by,query-optimization,Sql,Postgresql,Join,Group By,Query Optimization,至少有两个类似的问题(但不完全相同)。在这些问题中,查询性能的问题在于缺少索引或谓词过多 但我的情况简单明了:3个表,每个表引用另一个表。每个被引用的表行上都有b树索引。以下是表格: CREATE TABLE region( id serial PRIMARY KEY, title VARCHAR (50) NOT NULL ); CREATE TABLE unit( id serial PRIMARY KEY, region_id INT NOT NULL REFER

至少有两个类似的问题(但不完全相同)。在这些问题中,查询性能的问题在于缺少索引或谓词过多

但我的情况简单明了:3个表,每个表引用另一个表。每个被引用的表行上都有b树索引。以下是表格:

CREATE TABLE region(
   id serial PRIMARY KEY,
   title VARCHAR (50) NOT NULL
);

CREATE TABLE unit(
   id serial PRIMARY KEY,
   region_id INT NOT NULL REFERENCES region(id)
);

CREATE TABLE unit_usage(
   id serial PRIMARY KEY,
   title VARCHAR (50) NOT NULL,
   unit_id INT NOT NULL REFERENCES unit(id)
);

CREATE INDEX ON unit ((region_id));
CREATE INDEX ON unit_usage ((unit_id));
CREATE INDEX ON unit_usage ((title));
unit_usage表中有30000000+行,unit表中有50000+行,region表中有65000+行。 我想要的是查询每个单位使用的区域的计数。大概是这样的:

WITH x AS
(
 select u.region_id as region_id, t.title as title
 from unit_usage t join unit u
 on t.unit_id = u.id
)
SELECT title, count(region_id) as found_in_regions
FROM x GROUP BY title;
在这里

此查询大约运行5分钟。太多了,我的极限是10秒左右。 我所尝试的:

重新塑造查询,如:

select u.region_id, t.title, count(t.id) 
from unit_usage t join unit u
on t.unit_id = u.id group by u.region_id, t.title;
执行时间相同

  • 设置enable_hashjoin=off;我已经去掉了Hash连接和Seq扫描,但这不会影响执行时间

    • 我会首先尝试正确的逻辑。如果您想计算不同区域的数量,那么我希望:

      我想要的是查询每单位使用的区域数


      这不会加快查询速度。但至少它应该返回正确的结果。如果是这样,那么您可以开始考虑如何使其正确。

      此查询的结果与第二个查询的结果相同。它可以更快,因为要连接的行更少:

      with uu as (
        select u.unit_id, u.title, count(*) cnt
          from unit_usage u
         group by u.unit_id, u.title
      )
      select u.region_id, uu.title, sum(cnt)
        from uu
          inner join unit u
            on uu.unit_id = u.id
       group by u.region_id, uu.title
      
      此索引可能有助于此查询(最好使用和不使用索引进行测试):


      对不起,我在写这个示例时出错了。我修复了topic/fiddle中的SQL。SQL(已修复)是正确的,它提供了所需的结果:与unit_用法中的每个单独标题相关的区域。
      count(distinct u.region_id)
      将始终等于1,因为您按主标题进行分组key@Sergey94 . . . 我不明白你的评论
      u.region\u id
      unit\u usage
      上的主键无关。请按uu.id查看您的
      分组。您正在按单元使用的主键进行分组。这就是为什么计数总是等于1。@Sergey94。谢谢。是OLAP还是OLTP?这是一个OLAP部分。查询不可能扫描+3亿行并在10秒内执行。您应该使用聚合创建其他表,或者使用使用计数将聚合列添加到unit表中。并在ETL期间计算此聚合。然后,您的查询将变成一个表的简单完全扫描。看起来是这样,但至少我很高兴有一半的时间。您的两个查询似乎并不相等,因为在第一个查询中,您按标题分组,而在第二个查询中,您按标题和区域id分组。在group by中包含标题是否如此重要?或者你可以按区域id分组?
      
      with uu as (
        select u.unit_id, u.title, count(*) cnt
          from unit_usage u
         group by u.unit_id, u.title
      )
      select u.region_id, uu.title, sum(cnt)
        from uu
          inner join unit u
            on uu.unit_id = u.id
       group by u.region_id, uu.title
      
      create index unit_usage_ix on unit_usage(unit_id, title);