【问题标题】:Performance issues on a join连接的性能问题
【发布时间】:2021-04-22 06:18:20
【问题描述】:

我要加入两张表现不佳的牌桌。

表 1:

Period Zone Country company product
01/01/2020 EMEA DE WKDM2 Product1
01/02/2020 EMEA DE PRL56 Product1
01/03/2020 EMEA UK ORD56 Product2
01/04/2020 EMEA DE GFDS Product3
01/05/2020 EMEA FR 24GFDSGF2 Product1
01/06/2020 EMEA DE 2GFSDG37 Product3
01/07/2020 EMEA IT 2GFDSG35 Product1
01/08/2020 EMEA DE 23GSFDG6 Product4
01/09/2020 EMEA DE 23GSFDG5 Product6
01/10/2020 EMEA IT 24GSFD1 Product1
01/11/2020 EMEA DE 23GSDF6 Product3
01/12/2020 EMEA FI 24GFSDG1 Product8

表2:

Period Zone Country Quarter Year company product
01/01/2020 EMEA DE 01/01/2020 01/01/2020 WKDM2 Product1
01/02/2020 EMEA DE 01/01/2020 01/01/2020 PRL56 Product1
01/03/2020 EMEA UK 01/01/2020 01/01/2020 ORD56 Product2
01/04/2020 EMEA DE 01/04/2020 01/01/2020 GFDS Product3
01/05/2020 EMEA FR 01/04/2020 01/01/2020 24GFDSGF2 Product1
01/06/2020 EMEA DE 01/04/2020 01/01/2020 2GFSDG37 Product3
01/07/2020 EMEA IT 01/07/2020 01/01/2020 2GFDSG35 Product1
01/08/2020 EMEA DE 01/07/2020 01/01/2020 23GSFDG6 Product4
01/09/2020 EMEA DE 01/07/2020 01/01/2020 23GSFDG5 Product6
01/10/2020 EMEA IT 01/10/2020 01/01/2020 24GSFD1 Product1
01/11/2020 EMEA DE 01/10/2020 01/01/2020 23GSDF6 Product3
01/12/2020 EMEA FI 01/10/2020 01/01/2020 24GFSDG1 Product8

在我的示例中,数据相同,但在 Production ENV 中,表 1 中的公司是事实来源。第二张桌子上的产品是事实的来源。

Table1 有 6M 行,table2 有 600K 行。

当我这样加入时,我的表现很差,我该如何改进?:

SELECT R."Period",R."Zone",R."Country",S."Quarter",S."Year",R."Company",S."Product"
FROM table1 AS R,
    table2 AS S 
WHERE R."Period" = S."Period"
AND R."Zone" = S."Zone"
AND R."Country"=S."Country"
 GROUP BY 1,2,3,4,5,6,7

更新:

测试数据集:

CREATE OR REPLACE TEMPORARY TABLE "TMP_TEST1" (
    "Period"  TIMESTAMP,
    "Country"     VARCHAR,
    "Quarter"    TIMESTAMP,
    "Year"    TIMESTAMP,
    "Company"    VARCHAR,
    "Product"    VARCHAR
);

INSERT INTO "TMP_TEST1" 
VALUES 
('01/01/2020','DE','01/01/2020    ','01/01/2020   ','WKDM2    ','Product1'),
('01/01/2020','DE','01/01/2020    ','01/01/2020   ','2GFSDG37  ','Product1'),
('01/02/2020','DE','01/01/2020    ','01/01/2020   ','ORD56    ','Product2'),
('01/03/2020','DE','01/01/2020    ','01/01/2020   ','GFDS     ','Product3'),
('01/03/2020','DE','01/01/2020    ','01/01/2020   ','24GFDSGF2 ','Product1'),
('01/03/2020','DE','01/01/2020    ','01/01/2020   ','24GSFD1   ','Product1'),
('01/04/2020','DE','01/04/2020    ','01/01/2020   ','2GFSDG37  ','Product4'),
('01/04/2020','DE','01/04/2020     ','01/01/2020      ','23GSFDG5  ','Product6'),
('01/05/2020','DE','01/04/2020    ','01/01/2020   ','23GSDF6   ','Product3'),
('01/06/2020','DE','01/04/2020    ','01/01/2020   ','24GSFD1   ','Product8');

CREATE OR REPLACE TEMPORARY TABLE "TMP_TEST2" (
    "Period"  TIMESTAMP,
    "Country"     VARCHAR,
    "Quarter"    TIMESTAMP,
    "Year"    TIMESTAMP,
    "Company"    VARCHAR,
    "Product"    VARCHAR
);

INSERT INTO "TMP_TEST2" 
VALUES 
('01/01/2020','DE','01/01/2020    ','01/01/2020   ','WKDM2    ','Product1'),
('01/01/2020','DE','01/01/2020    ','01/01/2020   ','2GFSDG37  ','Product1'),
('01/02/2020','DE','01/01/2020    ','01/01/2020   ','ORD56    ','Product2'),
('01/03/2020','DE','01/01/2020    ','01/01/2020   ','GFDS     ','Product3'),
('01/03/2020','DE','01/01/2020    ','01/01/2020   ','24GFDSGF2 ','Product1'),
('01/03/2020','DE','01/01/2020    ','01/01/2020   ','2GFSDG37  ','Product3'),
('01/03/2020','DE','01/01/2020    ','01/01/2020   ','24GSFD1   ','Product1'),
('01/04/2020','DE','01/04/2020    ','01/01/2020   ','2GFSDG37  ','Product4'),
('01/04/2020','DE','01/04/2020     ','01/01/2020      ','23GSFDG5  ','Product6'),
('01/04/2020','DE','01/04/2020     ','01/01/2020      ','24GSFD1   ','Product1'),
('01/05/2020','DE','01/04/2020    ','01/01/2020   ','23GSDF6   ','Product3'),
('01/05/2020','DE','01/04/2020    ','01/01/2020   ','23GSDF6   ','Product9'),
('01/06/2020','DE','01/04/2020    ','01/01/2020   ','24GSFD1   ','Product8');

查询:

SELECT DISTINCT T1."Period",
    T1."Country",
    T1."Quarter",
    T1."Year",
    T1."Company",
    T2."Product"
FROM TMP_TEST1 AS T1 INNER JOIN TMP_TEST2 AS T2 
ON T1."Period" = T2."Period"
AND T1."Country"=T2."Country"
GROUP BY  1,2,3,4,5,6

使用此测试数据集,您将看到在没有公司时我会丢失产品。我不知道如何打破这种关系。我希望我对你来说足够清楚。

【问题讨论】:

    标签: performance join snowflake-cloud-data-platform


    【解决方案1】:

    首先,给定您显示的2个源表中的数据,请同时提供您希望看到的结果。

    对于你给出的查询,正确的写法,使用ANSI SQL,如下:

    SELECT R."Period",R."Zone",R."Country",S."Quarter",S."Year",R."Company",S."Product"
    FROM table1 AS R
    INNER JOIN table2 AS S ON
    R."Period" = S."Period"
    AND R."Zone" = S."Zone"
    AND R."Country"=S."Country"
     GROUP BY 1,2,3,4,5,6,7
    

    重复我的问题(并添加更多)

    1. 查询当前需要多长时间?
    2. 大概需要多长时间才能让您认为性能可以接受?
    3. 当您的查询中没有聚合函数时,为什么要使用 GROUP BY?如果您想要一个不同的列表(并且您的查询肯定会产生重复),请使用 SELECT DISTINCT...
    4. “笛卡尔计算”是什么意思?您的意思是笛卡尔连接吗?如果有,为什么要提到它们,因为您没有笛卡尔连接?

    回复评论

    ANSI SQL 连接更易于阅读(和调试),因为所有连接信息都在 JOIN 语句中,所有过滤条件都在 WHERE 语句中 - 而且它是行业标准,因此对于作为初学者,您现在应该习惯使用它,而不是学习不好的做法。想象一下,如果您使用内/外/左/右连接混合连接 20 个表 - 您使用的语法将非常难以理解,而 ANSI SQL 连接语法很容易理解。

    1. 您仍然没有根据您的源表提供您期望看到的输出 - 因此任何试图帮助您的人都只能猜测您想要实现的目标。
    2. 您也没有提供解释计划,因此没有人可以看到您的查询是如何执行的,因此可能会出现什么问题。在 Snowflake 中,转到 History,点击相关的 Query ID,点击 Profile,然后附上一个屏幕截图,显示正在运行的所有步骤、执行时间、统计信息等。

    【讨论】:

      【解决方案2】:

      所以我开始制作一些具有 6M 行数据和 600K 的表,以显示通过 text 进行连接的情况如何不好并使用 id's

      CREATE TABLE table1 AS
      with periods AS (
          SELECT dateadd('day', SEQ8(), '1999-01-01'::date) as period
          FROM TABLE(GENERATOR(rowcount=>1000))
      ), zones AS (
          SELECT column1 as zone
              ,seq8() as zone_id
          FROM VALUES ('EMEA')
      ), countries AS (
          SELECT column1 as country 
              ,seq8() as country_id  
          FROM VALUES ('DE'),('UK'),('FR'),('IT'),('NZ'),('AU'),('US'),('CA'),('xx'),('yy')
      ), company AS (
          SELECT seq8() as comp_id
              ,hash(comp_id) as h_comp_id
              ,h_comp_id::text as t_h_comp_id
          FROM TABLE(GENERATOR(rowcount=>600))
      )
      SELECT p.*, z.*, c.*, co.*
      FROM periods p
      JOIN zones z ON true
      JOIN countries c ON true
      JOIN company co ON true
      
      ;
      
      CREATE TABLE table2 AS
      SELECT *, YEAR(period) as year, QUARTER(period) as quarter
      FROM table1
      LIMIT 600000;
      

      然后运行 ​​SQL

      SELECT R.Period,R.Zone,R.Country,S.Quarter,S.Year,R.comp_id
      FROM table1 AS R
      JOIN table2 AS S
          ON  R.Period = S.Period
            AND R.Zone = S.Zone
            AND R.Country=S.Country;
      -- 1m27s
      

      这需要很长时间,所以运行了我的“快速”SQL

      SELECT R.Period,R.Zone,R.Country,S.Quarter,S.Year,R.comp_id
      FROM table1 AS R
      JOIN table2 AS S
          ON  R.Period = S.Period
            AND R.Zone_id = S.Zone_id
            AND R.Country_id=S.Country_id;
      -- 1m18s
      

      这也需要很长时间。 查看配置文件 90% 的时间都可以得到结果。

      SELECT S.Year, count(*) as c
      FROM table1 AS R
      JOIN table2 AS S
          ON  R.Period = S.Period
            AND R.Zone = S.Zone
            AND R.Country=S.Country
      GROUP BY 1;
      -- 9s
      

      交换到一个聚合以避免获取,错误的连接是 9 秒

      SELECT S.Year, count(*) as c
      FROM table1 AS R
      JOIN table2 AS S
          ON  R.Period = S.Period
            AND R.Zone_id = S.Zone_id
            AND R.Country_id=S.Country_id
      GROUP BY 1;
      -- 6s
      

      良好的连接是 6 秒。所以文本“仍然很糟糕”,但真正获取 360 万行文本确实很慢。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多