全部產品
Search
文件中心

Database Autonomy Service:【通知】SQL模板化演算法最佳化

更新時間:Aug 30, 2024

2024年09月01日起,DAS對SQL模板化演算法進行逐步最佳化。

變更背景

慢SQL鏈路和SQL審計鏈路的資料分析中,都依賴對每條SQL進行SQL模板化處理,進而針對相同的模板進行彙總分析。當前這個操作存在一些問題,不能很好處理被截斷的SQL(由於被截斷的位置不確定,有時會導致模板數膨脹,不方便使用者聚類查看)。

變更時間

2024年09月01日起,會逐步對兩類鏈路進行升級。

說明

2024年09月01日更新後,SQL模板化演算法的迭代最佳化,不再另行告知,具體請以介面返回為準。

變更範圍

涉及的資料庫引擎包括:RDS MySQL、RDS PostgreSQL、RDS SQLServer、RDS MariaDB和PolarDB MySQL版。

變更內容

主要最佳化點:

  • 支援PostgreSQL 中$$ 作為字串常量定界符(delimiter)的模板化,並修複標識符被錯誤替換成問號的BUG。

    原始 SQL:

    UPDATE "study" SET "name" = 'xiaoming', "ext" = $${"math":90,"english":91}$$ where id=128;

    最佳化前:

    UPDATE ? SET ? = ?, ? = $${?:?,?:?}$$ where id=?;

    最佳化後:

    UPDATE "study" SET "name"=?,"ext"=? WHERE id=?;
  • 對錶名和列名的數字尾碼進行替換,減少模板數量。

    原始 SQL:

    select * from [school_3].[class].[student_25];

    最佳化前:

    select * from [school_3].[class].[student_25];

    最佳化後:

    SELECT * FROM [school_?].[class].[student_?];
  • 針對 SQLServer,去掉首碼,正確解析 sql_type。

    原始 SQL:

    (@P0 nvarchar(4000))select id, name from student WHERE name = @P0;

    最佳化前:

    模板: (@P0 nvarchar(?))select id, name from student WHERE name = @P0;
    解析後的sql_type: p0

    最佳化後:

    模板: SELECT id,name FROM student WHERE name=?;
    解析後的sql_type: select
  • 保證文法正確的前提下,盡量減少空格,同時保留原始 SQL 中關鍵字的大小寫(不進行大寫轉換)。

    原始 SQL:

    select `name` from `student` 
      where `id` = 1 and (`name` = 'xiaoming' or `class` = 2);

    最佳化前:

    SELECT `name` FROM `student` WHERE `id` = ? AND (`name` = ? OR `class` = ?)

    最佳化後:

    SELECT `name` FROM `student` WHERE `id`=? AND (`name`=? OR `class`=?);
  • 完整保留原始 SQL 中的括弧。

    原始 SQL:

    select `name` from `student` where `id` = 1 and (`name` = 'xiaoming');

    最佳化前:

    SELECT `name` FROM `student` WHERE `id` = ? AND `name` = ?

    最佳化後:

    SELECT `name` FROM `student` WHERE `id`=? AND (`name`=?);
  • 不再將case運算式兩邊的括弧轉換為"AS"。

    原始 SQL:

    select `name`, ( CASE WHEN score > 90 THEN 'A' END ) `grade` from `student`;

    最佳化前:

    SELECT `name` , CASE  WHEN score > ? THEN ? END AS `grade` FROM `student`

    最佳化後:

    SELECT `name`,(CASE WHEN score>? THEN ? END)`grade` FROM `student`;
  • 正確解析"#"之後的內容。

    原始 SQL:

    select `name`, `#grade` from `student`;

    最佳化前:

    SELECT `name`, `

    最佳化後:

    SELECT `name`,`#grade` FROM `student`;
  • 處理截斷 SQL 時,丟棄不完整括弧內所有內容,減少模板數量。

    原始 SQL:

    select `name`, `grade` from `student` where id = (select uid from 

    最佳化前:

    select `name`, `grade` from `student` where id = (select uid from

    最佳化後:

    SELECT `name`,`grade` FROM `student` WHERE id=
  • 相似運算式進行合并,避免由於相似運算式個數不同導致的模板膨脹。

    原始 SQL:

    SELECT 
        CASE 
            WHEN score >= 90 THEN 'A'
            WHEN score >= 80 THEN 'B'
            WHEN score >= 70 THEN 'C'
            WHEN score >= 60 THEN 'D'
            ELSE 'F'
        END AS grade
    FROM 
        students;

    最佳化前:

    SELECT CASE  WHEN score >= ? THEN ? WHEN score >= ? THEN ? WHEN score >= ? THEN ? WHEN score >= ? THEN ? ELSE ? END AS grade FROM students

    最佳化後:

    SELECT CASE WHEN score>=? THEN ? ELSE ? END AS grade FROM students;

變更影響

  • 調用慢SQL的OpenAPI介面DescribeSlowLogsDescribeSlowLogRecords時,SQLText(SQL語句)對應的SQLHash(SQL模板標識符)的值會變化。

  • 調用SQL洞察的OpenAPI介面GetFullRequestStatResultByInstanceIdGetAsyncErrorRequestListByCode時,SqlId(SQL模板標識符)的值會變化。