由于数据分布和查询复杂度等因素,可能出现查询性能不符合预期的情况,检查查询的执行计划是重要的问题排查方式之一。

常见计划问题

  • Join Method以及Inner和Outer表

    根据Join Method选择Inner和Outer表, 一般情况下AnalyticDB MySQL版自动选择Join的左右表,您也可以自行检查左右表的选择是否合理。

    Hash Join中,右表创建Hash,左表去右表中查找符合条件的数据,一般右表要尽量小于左表,以减少创建Hash表的开销以及Hash表的大小。您可以通过检查Join表过滤后的大小来查看对应的左右表选择是否合理。但由于还有多表Join的中间结果,以及Join Type等因素影响,Join的左右表的选择也不能单纯依赖表过滤后的大小来选择。

  • Join Order

    Join Order的优化是优化器的核心挑战之一,也是经典的NP-hard问题。AnalyticDB MySQL版优化器对于不同的负载提供两种Join Reordering策略。Left Deep Tree(LDT)一般适用于较简单查询场景,Bushy Tree(BT)适用较复杂的负载查询。Bushy Tree一般会将过滤效果更好的表放在前面,对于复杂查询能够生成更优的Join Order。

    对于复杂查询,人为确认最佳Join Order非常困难。Join表数量较大时,需要资深的专家进行调优。建议将过滤效果更好的表放在Join Sequence之前,可以更早更快的过滤掉不需要的数据。

  • 分布式Aggregation

    AnalyticDB MySQL版提供分布式聚合计算能力,可以根据计算数据量分步做聚合计算。一般情况下,AnalyticDB MySQL版的优化器可以选择最佳聚合计算计划,但在数据倾斜比较严重等场景下,优化器对于聚合数据分布估算的误差会比较大,从而造成聚合计算性能问题。例如,一般AnalyticDB MySQL版会选择两阶段聚合计算,在各个计算节点本地做一次部分聚合(Partial Aggregation),减少聚合计算数据量,然后再根据聚合列Reshuffle做一次Final Aggregation。一般情况下,部分聚合可以显著减少聚合计算的数据量,但如果遇到数据倾斜严重,或者部分聚合列比较Unique从而不能减少聚合计算数量的情况下,部分聚合反而会带来额外的性能开销而非收益。

  • 其它问题

    本文只列举了几类常见的查询计划问题,例如全表扫描时出现无过滤条件的大表、可以下推的过滤条件没有下沉到存储等复杂计划和性能问题等,需要AnalyticDB MySQL版专家服务小组来协助定位排查。

改进执行计划

  • 收集统计信息

    AnalyticDB MySQL版的查询优化器根据统计信息估算不同计划的开销,并选择最佳计划。统计信息会自动收集,一般不需要用户关心,详情请参见自动收集统计信息。对于新建的表,系统可能还未及时收集统计信息,您可以通过select * from information_schema.column_statistics; 查看查询关联的表是否有统计信息(3.1.6及之后的版本才有此系统表)。如果查询关联的表没有统计信息,可以先手动执行收集命令收集一次,之后交给自动收集模块去收集即可。手动收集统计信息的详情,请参见手动收集统计信息

  • 调整Join Order

    通常AnalyticDB for MySQL可以选择最佳的Join Order,由于数据分布特性以及查询自身的复杂度等因素,在某些场景下可能存在无法选择最优Join Order,查询性能较低,您可以通过在Hint中引入reorder_joins参数设置是否手动调整Join Order。

    • /*+reorder_joins=false*/;,打开手动调整Join Order开关,然后通过修改查询中各个表出现的顺序来控制Join Order。
    • /*+reorder_joins=true*/;,关闭手动调整Join Order开关,系统会自动选择Join Order,绝大多数场景下可以获得最佳Join Order。
    例如上述示例中的nation、region、customer表,AnalyticDB MySQL版给出的Join Order是region > nation > customer。如果根据实际查询性能得出更好的Join Order:customer > nation > region,可以如下所示在查询前使用Hint改变查询中表的顺序。
    /*+ reorder_joins=false */
           EXPLAIN SELECT count(*)
           FROM    customer, nation, region
           WHERE c_nationkey = n_nationkey
           AND n_regionkey = r_regionkey
           AND r_name = 'ASIA';                       
           | Plan Summary  |
           +---------------+
           1- Output[ Query plan ]
           2  -> Aggregate (FINAL)
           3    -> LocalExchange[SINGLE]
           4      -> Exchange[GATHER]
           5        -> Aggregate (PARTIAL)
           6          -> InnerJoin[Hash Join]
           7            - Project
           8              -> InnerJoin[Hash Join]
           9                - ScanProject {table: customer}
           10                  -> TableScan {table: customer}
           11                -> LocalExchange[HASH]
           12                  -> Exchange[REPLICATE]
           13                    - ScanProject {table: nation}
           14                      -> TableScan {table: nation}
           15            -> LocalExchange[HASH]
           16              -> Exchange[REPLICATE]
           17                - ScanProject {table: region}
           18                  -> TableScan {table: region}                    

查询计划调优是一个非常广泛的领域,本文简要讨论AnalyticDB MySQL版中的查询计划调优基础方法,后续将不断更新更多的调优最佳实践。