• Azure Synapse Analytics 性能优化指南(3)——使用具体化视图优化性能(下)


    目录

    (一)前言

    (二)设计指南

    1. 针对工作负载设计

    2. 注意快速查询和成本之间的权衡

    3. 并非所有性能优化都需要更改查询

    4. 监视具体化视图

    5. 具体化视图和结果集缓存

    (三)示例


    (一)前言

           承接Azure Synapse Analytics 性能优化指南(2)一文,本文我们将继续探讨Azure Synapse Analytics中使用具体化视图优化性能。  

    (二)设计指南

    下面是关于使用具体化视图提高查询性能的一般指南:

    1. 针对工作负载设计

           在开始创建具体化视图之前,必须从查询模式、重要性、频率和生成的数据大小等方面深入了解工作负载。

           用户可以针对查询优化器建议的具体化视图运行 EXPLAIN WITH_RECOMMENDATIONS 。 由于这些建议特定于查询,因此对一个查询有利的具体化视图可能并不适合同一工作负载中的其他查询。

           评估这些建议时应考虑工作负载需要。 理想的具体化视图是那些有利于工作负载性能的视图。

    2. 注意快速查询和成本之间的权衡

           每个具体化视图都有相应的数据存储成本和视图维护成本。 当基表中的数据更改时,具体化视图的大小会增加,其物理结构也会改变。 为了避免查询性能下降,每个具体化视图会由 SQL 引擎单独维护。

           当具体化视图和基表更改的数量增加时,维护工作负载会增加。 用户应该检查查询性能的提高是否可以弥补所有具体化视图所产生的成本。

           可运行以下查询来生成专用 SQL 池中的具体化视图列表:

    1. SELECT V.name as materialized_view, V.object_id
    2. FROM sys.views V
    3. JOIN sys.indexes I ON V.object_id= I.object_id AND I.index_id < 2;

    减少具体化视图数量的选项:

    • 确定工作负载中的复杂查询经常使用的常见数据集。 创建具体化视图来存储这些数据集,以便优化器可以在创建执行计划时将它们用作构建基块。

    • 删除使用率低或不再需要的具体化视图。 禁用的具体化视图不会得到维护,但仍会产生存储成本。

    • 合并在相同或相似基表上创建的具体化视图,即使它们的数据没有重叠。 合并具体化视图可能导致视图的大小大于单独视图的总和,但是视图维护成本应该会降低。 例如:

    1. -- Query 1 would benefit from having a materialized view created with this SELECT statement
    2. SELECT A, SUM(B)
    3. FROM T
    4. GROUP BY A
    5. -- Query 2 would benefit from having a materialized view created with this SELECT statement
    6. SELECT C, SUM(D)
    7. FROM T
    8. GROUP BY C
    9. -- You could create a single mateiralized view of this form
    10. SELECT A, C, SUM(B), SUM(D)
    11. FROM T
    12. GROUP BY A, C

    3. 并非所有性能优化都需要更改查询

           SQL 查询优化器可以自动使用部署的具体化视图来改善查询性能。 此支持透明地应用于不引用视图的查询和使用具体化视图创建中不支持的聚合的查询。 无需更改任何查询。 可以检查查询的预估执行计划,确认是否使用了具体化视图。

    4. 监视具体化视图

           与使用聚集列存储索引 (CCI) 的表一样,具体化视图存储在专用 SQL 池中。 从具体化视图读取数据包括扫描 CCI 索引段和应用基表中的任何增量更改。 当增量更改的数量太多时,从具体化视图解析查询可能比直接查询基表花费更长的时间。

    为了避免查询性能下降,最佳做法是运行DBCC PDW_SHOWMATERIALIZEDVIEWOVERHEAD 来监视视图的 overhead_ratio (total_rows / max(1, base_view_row))。 如果具体化视图的 overhead_ratio 过高,则用户应重新生成该视图。

    5. 具体化视图和结果集缓存

           专用 SQL 池中的这两项功能用于优化查询性能。 结果集缓存用于获得高并发性,使针对静态数据的重复查询快速返回响应。

           为使用缓存结果,请求缓存的查询的形式必须与生成缓存的查询匹配。 此外,缓存的结果必须应用于整个查询。

           具体化视图允许基表中的数据更改。 具体化视图中的数据可以应用于查询的一部分。 借助这一支持,使用相同的某些计算的不同查询可使用相同的具体化视图,以获得更快的性能。

    (三)示例

           本例使用类似 TPCDS 的查询,查找通过目录支出比在商店花费更多资金的客户,确定首选客户及其原产国家/地区。 查询包括从涉及 SUM() 和 GROUP BY 的三个子 SELECT 语句的并集中选择前 100 条记录。

    1. WITH year_total AS (
    2. SELECT c_customer_id customer_id
    3. ,c_first_name customer_first_name
    4. ,c_last_name customer_last_name
    5. ,c_preferred_cust_flag customer_preferred_cust_flag
    6. ,c_birth_country customer_birth_country
    7. ,c_login customer_login
    8. ,c_email_address customer_email_address
    9. ,d_year dyear
    10. ,sum(isnull(ss_ext_list_price-ss_ext_wholesale_cost-ss_ext_discount_amt+ss_ext_sales_price, 0)/2) year_total
    11. ,'s' sale_type
    12. FROM customer
    13. ,store_sales
    14. ,date_dim
    15. WHERE c_customer_sk = ss_customer_sk
    16. AND ss_sold_date_sk = d_date_sk
    17. GROUP BY c_customer_id
    18. ,c_first_name
    19. ,c_last_name
    20. ,c_preferred_cust_flag
    21. ,c_birth_country
    22. ,c_login
    23. ,c_email_address
    24. ,d_year
    25. UNION ALL
    26. SELECT c_customer_id customer_id
    27. ,c_first_name customer_first_name
    28. ,c_last_name customer_last_name
    29. ,c_preferred_cust_flag customer_preferred_cust_flag
    30. ,c_birth_country customer_birth_country
    31. ,c_login customer_login
    32. ,c_email_address customer_email_address
    33. ,d_year dyear
    34. ,sum(isnull(cs_ext_list_price-cs_ext_wholesale_cost-cs_ext_discount_amt+cs_ext_sales_price, 0)/2) year_total
    35. ,'c' sale_type
    36. FROM customer
    37. ,catalog_sales
    38. ,date_dim
    39. WHERE c_customer_sk = cs_bill_customer_sk
    40. AND cs_sold_date_sk = d_date_sk
    41. GROUP BY c_customer_id
    42. ,c_first_name
    43. ,c_last_name
    44. ,c_preferred_cust_flag
    45. ,c_birth_country
    46. ,c_login
    47. ,c_email_address
    48. ,d_year
    49. UNION ALL
    50. SELECT c_customer_id customer_id
    51. ,c_first_name customer_first_name
    52. ,c_last_name customer_last_name
    53. ,c_preferred_cust_flag customer_preferred_cust_flag
    54. ,c_birth_country customer_birth_country
    55. ,c_login customer_login
    56. ,c_email_address customer_email_address
    57. ,d_year dyear
    58. ,sum(isnull(ws_ext_list_price-ws_ext_wholesale_cost-ws_ext_discount_amt+ws_ext_sales_price, 0)/2) year_total
    59. ,'w' sale_type
    60. FROM customer
    61. ,web_sales
    62. ,date_dim
    63. WHERE c_customer_sk = ws_bill_customer_sk
    64. AND ws_sold_date_sk = d_date_sk
    65. GROUP BY c_customer_id
    66. ,c_first_name
    67. ,c_last_name
    68. ,c_preferred_cust_flag
    69. ,c_birth_country
    70. ,c_login
    71. ,c_email_address
    72. ,d_year
    73. )
    74. SELECT TOP 100
    75. t_s_secyear.customer_id
    76. ,t_s_secyear.customer_first_name
    77. ,t_s_secyear.customer_last_name
    78. ,t_s_secyear.customer_birth_country
    79. FROM year_total t_s_firstyear
    80. ,year_total t_s_secyear
    81. ,year_total t_c_firstyear
    82. ,year_total t_c_secyear
    83. ,year_total t_w_firstyear
    84. ,year_total t_w_secyear
    85. WHERE t_s_secyear.customer_id = t_s_firstyear.customer_id
    86. AND t_s_firstyear.customer_id = t_c_secyear.customer_id
    87. AND t_s_firstyear.customer_id = t_c_firstyear.customer_id
    88. AND t_s_firstyear.customer_id = t_w_firstyear.customer_id
    89. AND t_s_firstyear.customer_id = t_w_secyear.customer_id
    90. AND t_s_firstyear.sale_type = 's'
    91. AND t_c_firstyear.sale_type = 'c'
    92. AND t_w_firstyear.sale_type = 'w'
    93. AND t_s_secyear.sale_type = 's'
    94. AND t_c_secyear.sale_type = 'c'
    95. AND t_w_secyear.sale_type = 'w'
    96. AND t_s_firstyear.dyear+0 = 1999
    97. AND t_s_secyear.dyear+0 = 1999+1
    98. AND t_c_firstyear.dyear+0 = 1999
    99. AND t_c_secyear.dyear+0 = 1999+1
    100. AND t_w_firstyear.dyear+0 = 1999
    101. AND t_w_secyear.dyear+0 = 1999+1
    102. AND t_s_firstyear.year_total > 0
    103. AND t_c_firstyear.year_total > 0
    104. AND t_w_firstyear.year_total > 0
    105. AND CASE WHEN t_c_firstyear.year_total > 0 THEN t_c_secyear.year_total / t_c_firstyear.year_total ELSE NULL END
    106. > CASE WHEN t_s_firstyear.year_total > 0 THEN t_s_secyear.year_total / t_s_firstyear.year_total ELSE NULL END
    107. AND CASE WHEN t_c_firstyear.year_total > 0 THEN t_c_secyear.year_total / t_c_firstyear.year_total ELSE NULL END
    108. > CASE WHEN t_w_firstyear.year_total > 0 THEN t_w_secyear.year_total / t_w_firstyear.year_total ELSE NULL END
    109. ORDER BY t_s_secyear.customer_id
    110. ,t_s_secyear.customer_first_name
    111. ,t_s_secyear.customer_last_name
    112. ,t_s_secyear.customer_birth_country
    113. OPTION ( LABEL = 'Query04-af359846-253-3');

           

           检查查询的预估执行计划。 共有 18 个随机排布和 17 个联接操作,执行这些操作需要更多的时间。 现在让我们为三个子 SELECT 语句分别创建一个具体化视图。

    1. CREATE materialized view nbViewSS WITH (DISTRIBUTION=HASH(customer_id)) AS
    2. SELECT c_customer_id customer_id
    3. ,c_first_name customer_first_name
    4. ,c_last_name customer_last_name
    5. ,c_preferred_cust_flag customer_preferred_cust_flag
    6. ,c_birth_country customer_birth_country
    7. ,c_login customer_login
    8. ,c_email_address customer_email_address
    9. ,d_year dyear
    10. ,sum(isnull(ss_ext_list_price-ss_ext_wholesale_cost-ss_ext_discount_amt+ss_ext_sales_price, 0)/2) year_total
    11. , count_big(*) AS cb
    12. FROM dbo.customer
    13. ,dbo.store_sales
    14. ,dbo.date_dim
    15. WHERE c_customer_sk = ss_customer_sk
    16. AND ss_sold_date_sk = d_date_sk
    17. GROUP BY c_customer_id
    18. ,c_first_name
    19. ,c_last_name
    20. ,c_preferred_cust_flag
    21. ,c_birth_country
    22. ,c_login
    23. ,c_email_address
    24. ,d_year
    25. GO
    26. CREATE materialized view nbViewCS WITH (DISTRIBUTION=HASH(customer_id)) AS
    27. SELECT c_customer_id customer_id
    28. ,c_first_name customer_first_name
    29. ,c_last_name customer_last_name
    30. ,c_preferred_cust_flag customer_preferred_cust_flag
    31. ,c_birth_country customer_birth_country
    32. ,c_login customer_login
    33. ,c_email_address customer_email_address
    34. ,d_year dyear
    35. ,sum(isnull(cs_ext_list_price-cs_ext_wholesale_cost-cs_ext_discount_amt+cs_ext_sales_price, 0)/2) year_total
    36. , count_big(*) as cb
    37. FROM dbo.customer
    38. ,dbo.catalog_sales
    39. ,dbo.date_dim
    40. WHERE c_customer_sk = cs_bill_customer_sk
    41. AND cs_sold_date_sk = d_date_sk
    42. GROUP BY c_customer_id
    43. ,c_first_name
    44. ,c_last_name
    45. ,c_preferred_cust_flag
    46. ,c_birth_country
    47. ,c_login
    48. ,c_email_address
    49. ,d_year
    50. GO
    51. CREATE materialized view nbViewWS WITH (DISTRIBUTION=HASH(customer_id)) AS
    52. SELECT c_customer_id customer_id
    53. ,c_first_name customer_first_name
    54. ,c_last_name customer_last_name
    55. ,c_preferred_cust_flag customer_preferred_cust_flag
    56. ,c_birth_country customer_birth_country
    57. ,c_login customer_login
    58. ,c_email_address customer_email_address
    59. ,d_year dyear
    60. ,sum(isnull(ws_ext_list_price-ws_ext_wholesale_cost-ws_ext_discount_amt+ws_ext_sales_price, 0)/2) year_total
    61. , count_big(*) AS cb
    62. FROM dbo.customer
    63. ,dbo.web_sales
    64. ,dbo.date_dim
    65. WHERE c_customer_sk = ws_bill_customer_sk
    66. AND ws_sold_date_sk = d_date_sk
    67. GROUP BY c_customer_id
    68. ,c_first_name
    69. ,c_last_name
    70. ,c_preferred_cust_flag
    71. ,c_birth_country
    72. ,c_login
    73. ,c_email_address
    74. ,d_year

           再次检查原始查询的执行计划。 现在,联接数从 17 个更改为 5 个,并且没有随机排布。 选择计划中的“筛选操作”图标,其“输出列表”将显示已从具体化视图而不是基表读取了数据。

           使用具体化视图时,同一查询的运行速度更快,且无需进行任何代码更改。 

  • 相关阅读:
    搞了三天终于成功跑起来GitHub上的vue-element-admin最新解决办法!(mac系统亲测有效)
    不用入耳就有好音质,南卡OE Pro 0压开放式耳机
    可以直接打开小皮面板中的网站运行php文件,昨天下载了数据库插件,一直提示“服务器连接错误,如何解决?(相关搜索:建立数据库)
    el-form-item validator 携带额外的参数
    网上选课系统的设计与实现(ASP.NET)
    springboot设置并获取启动参数
    05-java数据结构之递归的详细介绍与学习
    问题与分类
    docker容器添加对外映射端口
    naiveui的table实现可滚动的恒居中空数据处理
  • 原文地址:https://blog.csdn.net/zyypjc/article/details/125989388