当连接多个小表时,如何提高snowflake中sql查询的性能?

ecfsfe2w  于 2021-07-26  发布在  Java
关注(0)|答案(3)|浏览(354)

我目前正在与星展在雪花,我有一个性能问题。
在我的查询中,我需要从包含其他表外键的主表中检索100行数据。主表大小介于50k-300k行之间。
这个主表包含类型为number(38,0)的id(外键),这些字段/列的描述是通过直接的内部联接从其他表中检索的。
辅助表(表1、表2……)非常小,所有表的行数都不到20行,只有一个表的行数在1500行左右(仍然非常小)
问题是:
运行查询(如下所示)平均需要1.7秒才能完成。如果删除所有desc字段(使用内部联接检索)和所有内部联接,则查询平均需要300毫秒才能完成。
我的同行实施的当前解决方案:
他们缓存了我们应用程序中所有辅助表的信息(用java制作,但这是不相关的)。对于大约80%的情况(参见下面的查询),我们不需要按描述过滤,这是可行的,但是对于其他20%的情况,我们仍然需要执行内部连接。
缩小解决方案的规模:
不是一个坏的解决方案,但它有两个问题:
(还不错)它膨胀了我们的代码库,基本上是一个java的“连接”
有20%的时间我们需要通过描述进行过滤,我们仍然需要进行内部连接,因此我们仍然存在性能问题。
我想到的一种可能性是将这些表缓存在sf中,但我还没有找到一种直接的方法。也许有一种方法可以优化查询,但我还不了解snowflake在内部是如何工作的,据我所知,它不使用索引,至少与其他平台不一样。
那么,有没有一种方法可以为100%的案例优化sf中的查询?

SELECT 
  main_table.ONE_ID, 
  main_table.TWO_ID, 
  main_table.THREE_ID, 
  main_table.FOUR_ID, 
  main_table.FIVE_ID, 
  main_table.SIX_ID, 
  main_table.SEVEN_ID, 
  field_one.ONE_DESC, 
  field_two.TWO_DESC, 
  field_three.THREE_DESC,
  field_four.FOUR_DESC, 
  field_five.FIVE_DESC, 
  field_six.SIX_DESC, 
  field_seven.SEVEN_DESC

FROM 
  SOME_DATABASE.MAIN_TABLE AS main_table 

  INNER JOIN SOME_DATABASE.TABLE_ONE    AS table_one    ON main_table.field_one_id =    table_one    .ONE_ID
  INNER JOIN SOME_DATABASE.TABLE_TWO    AS table_two    ON main_table.field_two_id =    table_two    .TWO_ID
  INNER JOIN SOME_DATABASE.TABLE_THREE  AS table_tree   ON main_table.field_tree_id =   table_tree   .THREE_ID
  INNER JOIN SOME_DATABASE.TABLE_FOUR   AS table_four   ON main_table.field_four_id =   table_four   .FOUR_ID
  INNER JOIN SOME_DATABASE.TABLE_FIVE   AS table_five   ON main_table.field_five_id =   table_five   .FIVE_ID
  INNER JOIN SOME_DATABASE.TABLE_SIX    AS table_six    ON main_table.field_six_id =    table_six    .SIX_ID
  INNER JOIN SOME_DATABASE.TABLE_SEVEN  AS table_seven  ON main_table.field_seven_id =  table_seven  .SEVEN_ID

WHERE 
  main_table.ONE_ID IN (25, 26) 
  AND main_table.TWO_ID IN (10, 12) 
  AND main_table.THREE_ID IN (1, 2, 3) 
  AND main_table.FOUR_ID IN (2, 3) 
  AND main_table.FIVE_ID IN (3) 
  AND main_table.SEVEN_ID IN (1) 

  -- The following WHERE clauses are present in about 20% of the queries
  AND table_one.ONE_DESC, 
  AND table_two.TWO_DESC, 
  AND table_three.THREE_DESC,

ORDER BY 
  main_table.ONE_ID, 
  main_table.TWO_ID, 
  main_table.THREE_ID

LIMIT 
  100 OFFSET 0

小更新:
我一直在尝试使用with子句,包括 Package ID和描述,但似乎没有改进

envsm3lx

envsm3lx1#

我只是好奇,如果您使用子查询中主表上的筛选来表达查询,是否会有所不同:

FROM (SELECT *
      FROM main_table
      WHERE main_table.ONE_ID IN (25, 26) AND
            main_table.TWO_ID IN (10, 12) AND
            main_table.THREE_ID IN (1, 2, 3) AND
            main_table.FOUR_ID IN (2, 3) AND
            main_table.FIVE_ID IN (3) AND
            main_table.SEVEN_ID IN (1) 
     ) main_table JOIN
    . . .

巨大的可伸缩性的缺点之一是,所使用的方法会给较小的查询增加开销。也就是说,如果将表的大小乘以1000,查询可能只需要几秒钟——但这并不能帮助您在较小的数据上缩短时间。

chy5wohz

chy5wohz2#

你有没有试过重新设计你的字典表?就像你有一个:
dt1、dt2、dt3各有键、值
你可以试着把它变成
dt dictionary\u id、key、value
这一次不是5个小表,而是1个稍微大一点、稍微复杂一点的连接条件,因为您必须为每个表添加字典id,但所有表都可能在单个数据块而不是5个数据块中进行检索

7rfyedvj

7rfyedvj3#

我的第一个想法是,snowflake的设计不是为了快速提出这样的小问题,而是为了回答大问题。因此,对我来说1.xs是很好的响应时间。
但考虑到你想快点。。
我首先检查慢速查询的编译时间是否与快速查询的编译时间相同。因为如果您的表是碎片化的,则需要读取更多的元数据。
接下来,我将查看执行的概要,看看时间花在了哪里。过去我们发现

SELECT columnA, columnB FROM table where ID == 1
UNION ALL 
SELECT columnA, columnB FROM table where ID == 2

比…快

SELECT columnA, columnB FROM table where ID in (1,2)

噢,我们发现gordon在select from a table时显式地放置where子句,这有助于解决优化器的困惑。
但另一方面可能只是额外的数据传输到客户机所需的时间更长(如果您使用客户机时间作为判断标准),或者如果您查看webui中的性能,您读取的数据越多,运行查询所需的时间就越长。所以即使你建了一个新表

CREATE TABLE testo AS
SELECT 
  main_table.ONE_ID, 
  main_table.TWO_ID, 
  main_table.THREE_ID, 
  main_table.FOUR_ID, 
  main_table.FIVE_ID, 
  main_table.SIX_ID, 
  main_table.SEVEN_ID, 
  table_one.ONE_DESC, 
  table_two.TWO_DESC, 
  table_three.THREE_DESC,
  table_four.FOUR_DESC, 
  table_five.FIVE_DESC, 
  table_six.SIX_DESC, 
  table_seven.SEVEN_DESC
FROM 
    SOME_DATABASE.MAIN_TABLE AS main_table 
INNER JOIN SOME_DATABASE.TABLE_ONE AS table_one    
    ON main_table.field_one_id = table_one.ONE_ID
INNER JOIN SOME_DATABASE.TABLE_TWO AS table_two
    ON main_table.field_two_id = table_two.TWO_ID
INNER JOIN SOME_DATABASE.TABLE_THREE AS table_tree
    ON main_table.field_tree_id = table_tree.THREE_ID
INNER JOIN SOME_DATABASE.TABLE_FOUR AS table_four
    ON main_table.field_four_id = table_four.FOUR_ID
INNER JOIN SOME_DATABASE.TABLE_FIVE AS table_five
    ON main_table.field_five_id = table_five.FIVE_ID
INNER JOIN SOME_DATABASE.TABLE_SIX AS table_six
    ON main_table.field_six_id = table_six.SIX_ID
INNER JOIN SOME_DATABASE.TABLE_SEVEN AS table_seven  
    ON main_table.field_seven_id = table_seven.SEVEN_ID

然后再做

ONE_ID, 
    TWO_ID, 
    THREE_ID, 
    FOUR_ID, 
    FIVE_ID, 
    SIX_ID, 
    SEVEN_ID, 
    ONE_DESC, 
    TWO_DESC, 
    THREE_DESC,
    FOUR_DESC, 
    FIVE_DESC, 
    SIX_DESC, 
    SEVEN_DESC
FROM testo
WHERE 
    ONE_ID IN (25, 26) 
    AND TWO_ID IN (10, 12) 
    AND THREE_ID IN (1, 2, 3) 
    AND FOUR_ID IN (2, 3) 
    AND FIVE_ID IN (3) 
    AND SEVEN_ID IN (1)

所需时间将超过:

ONE_ID, 
    TWO_ID, 
    THREE_ID, 
    FOUR_ID, 
    FIVE_ID, 
    SIX_ID, 
    SEVEN_ID
FROM testo
WHERE 
    ONE_ID IN (25, 26) 
    AND TWO_ID IN (10, 12) 
    AND THREE_ID IN (1, 2, 3) 
    AND FOUR_ID IN (2, 3) 
    AND FIVE_ID IN (3) 
    AND SEVEN_ID IN (1)

最后,我知道它是示例代码,但是从 main_tablemain_table 因为这是已经存在的别名/名称。

相关问题