Postgres将获得5个中级SQL表到达所需的表

时间:2016-01-08 16:32:23

标签: sql postgresql

我正在制作关于选民数据的报告,这些数据将选民分组到他们的年龄组,然后在最终返回年龄组和四分位数表之前将这些年龄组分配为四分位数。

当我使用我想要的架构和数据到达表时,我创建了7个中间表,此时可能也会被删除。

我的问题是,是否需要这么多中间表?或者这表明我“做错了?”

技术细节:

Postgres 9.4

我正在链接表,从原始数据库表开始,并连续地将表转换为我想要的更接近的表。例如,我做了类似的事情:

CREATE TABLE gm.race_code_and_turnout_count AS
SELECT race_code, count(*)
FROM gm.active_dem_voters_34th_house_in_2012_primary
GROUP BY race_code

然后我做

CREATE TABLE gm.race_code_and_percent_of_total_turnout AS
SELECT race_code, count, round((count::numeric/11362)*100,2) AS   percent_of_total_turnout
FROM gm.race_code_and_turnout_count

第一个表格在第二个分支中出现:

CREATE TABLE gm.race_code_and_turnout_percentage AS
SELECT t1.race_code, round((t1.count::numeric / t2.count)*100,2) as turnout_percentage
FROM gm.race_code_and_turnout_count AS t1
JOIN gm.race_code_and_total_count AS t2
ON t1.race_code = t2.race_code

所以每张桌子都建在前面的那张桌子上。

2 个答案:

答案 0 :(得分:2)

虽然临时表在SQL Server中被大量使用(主要是为了克服它所具有的特殊锁定行为),但它在Postgres中很少见(并且您的示例使用常规表,而不是临时表)。

通常,创建新表的开销高于让系统将中间存储在磁盘上。

根据我的经验,创建中间表通常只有在以下情况下才有用:

  1. 您有一个很多的数据已汇总且无法在内存中汇总
  2. 聚合大大减少了要处理的数据量,以便下一步(或下一步之一)可以处理内存中的数据
  3. 您可以有效地索引中间表,以便下一步可以利用这些索引来提高性能。
  4. 您在不同的步骤中多次重复使用预先计算的结果
  5. 以上列表并不完全,如果只有其中一些条件成立,使用这种方法也会有所帮助。

    如果你继续创建这些表,至少要创建它们作为temporaryunlogged表,以最大限度地减少写入数据所带来的IO开销,从而保留尽可能多的数据在记忆中尽可能。

    但是我总是从一个查询开始,而不是维护许多不同的表(如果你必须改变报告的结构,那么所有表都需要更改。)

    例如,您问题的前两个查询可以很容易地合并到一个查询中,而不会丢失性能:

    SELECT race_code, 
           count(*) as cnt,
           round((count(*)::numeric/11362)*100,2) AS percent_of_total_turnout
    FROM gm.active_dem_voters_34th_house_in_2012_primary
    GROUP BY race_code;
    

    这比将数据两次写入磁盘要快(包括所有事务开销)。

    如果使用公共表表达式堆栈查询,Postgres会自动将数据存储在磁盘上(如果它太大,如果不是,它会在内存中处理它)。手动创建表时,强制 Postgres将所有内容写入磁盘。

    所以你可能想尝试这样的事情:

    with race_code_and_turnout_count as (
      SELECT race_code, 
             count(*) as cnt,
             round((count(*)::numeric/11362)*100,2) AS percent_of_total_turnout
      FROM gm.active_dem_voters_34th_house_in_2012_primary
      GROUP BY race_code
    ), race_code_and_total_count as (
       select ....
       from ....
    ), race_code_and_turnout_percentage as (
      SELECT t1.race_code, 
             round((t1.count::numeric / t2.count)*100,2) as turnout_percentage
      FROM ace_code_and_turnout_count AS t1
        JOIN race_code_and_total_count AS t2 
          ON t1.race_code = t2.race_code
    )
    select *
    from ....;
    

    并了解其表现如何。

    如果您不多次重复使用中间步骤,由于优化程序的工作方式,在Postgres中将它们写为派生表而不是CTE可能会更快,例如:

    SELECT t1.race_code, 
           round((t1.count::numeric / t2.count)*100,2) as turnout_percentage
    FROM (
      SELECT race_code, 
             count(*) as cnt,
             round((count(*)::numeric/11362)*100,2) AS percent_of_total_turnout
      FROM gm.active_dem_voters_34th_house_in_2012_primary
      GROUP BY race_code
    ) AS t1
      JOIN race_code_and_total_count AS t2 
        ON t1.race_code = t2.race_code
    

答案 1 :(得分:0)

如果它表现良好并产生正确的输出,我认为它没有任何问题。但是,如果您需要中间表,我建议使用(本地)临时表。

您可以始终优化一系列查询以使用更少的中间步骤。如果您认为报告开始表现不佳,请执行此操作。