當SQL查詢中包含冗餘的GROUP BY或ORDER BY子句時,資料庫需執行不必要的排序或雜湊計算,這會消耗大量CPU和記憶體資源。尤其在處理海量資料時,此類冗餘操作會嚴重影響分析型(AP)查詢的效能。PolarDB MySQL版的GROUP BY/ORDER BY消除功能,能夠基於函數依賴(Functional Dependency)自動識別並消除這類冗餘操作。您無需修改任何業務代碼,即可在分析型查詢情境下獲得顯著的效能提升(在TPC-H測試中最高可達29%),並降低資源消耗。
適用範圍
產品系列:叢集版、標準版。
核心版本:MySQL 8.0.2,且修訂版本需為8.0.2.2.33及以上版本。
開啟消除功能
通過設定loose_groupby_elimination_mode和loose_orderby_elimination_mode參數來控制此最佳化功能的行為。
PolarDB叢集參數在控制台與會話中修改方式存在差異,詳細區別如下:
在PolarDB控制台上修改:
相容性說明:部分叢集參數在PolarDB控制台上均已添加MySQL設定檔的相容性首碼loose_。
操作方法:找到並修改這些帶
loose_首碼的參數。
在資料庫會話中修改(使用命令列或用戶端):
操作方法:當您串連到資料庫,使用
SET命令修改參數時,請去掉loose_首碼,直接使用參數的原始名稱進行修改。
參數名稱 | 層級 | 描述 |
| Global/Session | 控制
|
| 控制
|
工作原理
GROUP BY/ORDER BY消除功能的核心是利用函數依賴(Functional Dependency,FD)。瞭解其工作原理有助於您更好地構造SQL,並預判最佳化是否能夠生效。
什麼是函數依賴:如果A列(或多列)的值能唯一確定B列的值,則稱B列函數依賴於A列,記為
A -> B。例如,在使用者表中,主鍵使用者ID能唯一確定使用者暱稱,因此存在函數依賴:使用者ID -> 使用者暱稱。最佳化器如何發現函數依賴:PolarDB的最佳化器主要通過以下中繼資料和查詢條件來自動推導函數依賴關係:
主鍵/唯一鍵:表結構中定義的
PRIMARY KEY或UNIQUE KEY是最直接的函數依賴來源。等值串連條件:通過
JOIN的等值條件(如t1.pk = t2.fk),主鍵的唯一性可以傳遞到關聯的表中。常量過濾條件:
WHERE子句中的等值過濾(如WHERE status = 'active')會使該列在結果集中成為一個常量。
核心最佳化規則:
消除GROUP BY:
如果
GROUP BY的列集合已經能唯一確定結果集中的每一行(例如,包含了某張表的主鍵),則整個GROUP BY運算元是冗餘的,可以被安全地消除。如果
GROUP BY的列集合均為常量,則可消除整個GROUP BY運算元,並添加LIMIT 1。
消除ORDER BY:如果
ORDER BY的列集合均為常量,則整個ORDER BY運算元是冗餘的,可以被安全地消除。簡化GROUP BY/ORDER BY:如果
GROUP BY或ORDER BY的列中存在函數依賴關係(如GROUP BY x, y,且已知x -> y),則可以簡化為GROUP BY x,減少參與分組或排序的列數。
典型最佳化情境與樣本
情境一:根據主鍵或唯一鍵分組
當GROUP BY子句中包含了表的主鍵或唯一鍵時,由於主鍵已能唯一確定一行資料,因此對其他列進行分組是多餘的。
業務情境:統計每個使用者的訂單總額,同時展示使用者名稱。
原始SQL:
-- user表的user_id是主鍵,可以唯一確定user_name SELECT u.user_id, u.user_name, COUNT(o.order_id) FROM user u JOIN orders o ON u.user_id = o.user_id GROUP BY u.user_id, u.user_name;最佳化分析:因為
user_id是主鍵,它唯一決定了user_name的值。最佳化器識別到user_id -> user_name的函數依賴關係,會自動將GROUP BY u.user_id, u.user_name簡化為GROUP BY u.user_id,從而消除對user_name的不必要分組操作。
情境二:根據常量分組
當GROUP BY子句中的所有列都是常量時,整個分組操作是冗餘的,因為結果集最多隻有一行。
業務情境:查詢某個特定使用者的特定狀態資訊(一種不常見的SQL寫法,但最佳化器能處理)。
原始SQL:
SELECT a, b FROM t1 WHERE a = 1 AND b = 1 GROUP BY a, b;最佳化分析:最佳化器識別到
GROUP BY的列a和b在WHERE子句中已被指定為常量,因此會直接消除GROUP BY運算元,並添加LIMIT 1。SELECT a, b FROM t1 WHERE a = 1 AND b = 1 LIMIT 1;
場景三:多表串連下的複雜分組(TPC-H Q10)
在多表JOIN的複雜查詢中,函數依賴關係可以通過串連條件進行傳導,最佳化器能夠利用這種傳導性來消除更複雜的冗餘分組。
原始SQL(TPC-H Q10):
SELECT c_custkey, c_name, c_acctbal, c_phone, n_name, c_address, c_comment, SUM(l_extendedprice * (1 - l_discount)) AS revenue FROM customer, orders, lineitem, nation WHERE c_custkey = o_custkey AND l_orderkey = o_orderkey AND c_nationkey = n_nationkey -- 其他過濾條件... GROUP BY c_custkey, c_name, c_acctbal, c_phone, n_name, c_address, c_comment ORDER BY revenue DESC LIMIT 20;最佳化分析:
主鍵依賴:在
customer表中,c_custkey是主鍵,因此它唯一決定了c_name、c_acctbal、c_phone、c_address、c_comment、c_nationkey等所有其他列。依賴傳導:由於
JOIN條件c_nationkey = n_nationkey,並且n_nationkey是nation表的主鍵(決定n_name),最佳化器可以推匯出c_custkey也唯一決定了n_name。最終簡化:綜上,
GROUP BY子句中的所有列(c_name、c_acctbal等)都函數依賴於c_custkey。因此,最佳化器可以將複雜的GROUP BY列表直接簡化為GROUP BY c_custkey,大幅減少了分組計算的複雜度。
SELECT c_custkey, c_name, c_acctbal, c_phone, n_name, c_address, c_comment, SUM(l_extendedprice * (1 - l_discount)) AS revenue FROM customer, orders, lineitem, nation WHERE c_custkey = o_custkey AND l_orderkey = o_orderkey AND c_nationkey = n_nationkey -- 其他過濾條件... GROUP BY c_custkey ORDER BY revenue DESC LIMIT 20;
情境四:Order By情境
當ORDER BY子句中的列存在函數依賴關係時,最佳化器可以簡化排序操作,減少參與排序的列數。
業務情境:對錶進行排序,其中某些列由其他列唯一確定。
表結構:
CREATE TABLE t1 ( a int, b int, c int as (a + b) unique not null );原始SQL:
EXPLAIN SELECT a, b FROM t1 ORDER BY a,b,c;最佳化分析 :由於列
c是由a和b計算得出的(c = a + b),並且c被定義為unique not null,因此存在函數依賴關係:(a, b) -> c。最佳化器識別到這一依賴關係後,會自動將ORDER BY a, b, c簡化為ORDER BY a, b,從而減少排序操作的複雜度。SHOW warnings; +-------+------+-------------------------------------------------------------------------------------------------------------------------------+ | Level | Code | Message | +-------+------+-------------------------------------------------------------------------------------------------------------------------------+ | Note | 1003 | /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` order by `test`.`t1`.`a`,`test`.`t1`.`b` | +-------+------+-------------------------------------------------------------------------------------------------------------------------------+
效能測試
在TPC-H 100 GB標準資料集上進行的測試表明,開啟GROUP BY消除功能後,Q10查詢的效能得到顯著提升。
本文的TPC-H的實現基於TPC-H的基準測試,並不能與發行的TPC-H基準測試結果相比較,本文中的測試並不完全符合TPC-H的所有要求。
以下資料僅為特定情境下的測試結果,實際效能提升效果可能因查詢複雜度、資料分布和叢集規格等因素而異。
測試情境 | 開啟 | 不開啟(執行時間) | 效能提升 |
使用列存索引(IMCI)在1 DOP(產生資料後1天內) | 48秒 | 68秒 | 29% |
使用列存索引(IMCI)在32 DOP(產生資料後32天內) | 1.9秒 | 2.6秒 | 27% |