數據查詢最佳實踐
在云原生數據倉庫AnalyticDB MySQL版中編寫和優化SQL時,需要充分考慮其分布式特性,本文匯總了SQL編寫和優化時的經驗和技巧供您參考。
經驗總結
編寫和優化SQL的經驗總結如下:
SQL編寫原則為追求簡單
一般情況下,數據庫性能會隨SQL復雜度而下降。例如,單表查詢(冗余設計)優于表關聯查詢。
SQL優化核心方法是減少I/O
盡可能少的進行列掃描,返回最小數據量,減少I/O同時也減少內存開銷。
分布式計算,本地計算&并行計算
大數據計算情況下,本地計算時充分利用分布式多計算資源的能力,避免數據跨節點。
高QPS,分區裁剪
業務系統要求高QPS、毫秒級RT時,表和SQL必須設計為分區裁剪模式。
SQL優化技巧
去掉不必要的列
云原生數據倉庫AnalyticDB MySQL版是行列混存數據庫,返回的列的數量直接影響性能,在編寫SQL時一定要確認業務需要返回的列,不要直接使用星號(*)進行查詢。
SQL示例。
錯誤SQL:
select * from tab1 where c1>100 and c1<1000;
正確SQL:
select col1, col2 from table_name where c1>100 and c1<1000;
索引和掃描
當SQL包含多個查詢條件時,優先選擇高篩選條件,其他條件可以通過掃描實現。
云原生數據倉庫AnalyticDB MySQL版內部采用行列混存方式,通過單列高效過濾后,可直接通過內部記錄指針掃描其他列值,減少其他列的索引查詢開銷。
云原生數據倉庫AnalyticDB MySQL版支持在查詢級別和集群級別針對特定字段關閉索引過濾,請參見過濾條件不下推。
示例
說明以下示例適用于3.14以下的內核版本。如果內核版本為3.14及以上,請使用
filter_not_pushdown_columns
Hint。time條件通過內部掃描
在SQL命令中通過條件
c1=3
可快速查詢到少量記錄(假設10000),單獨使用time>'2010-01-01 00:00:00'
時返回的記錄數又非常大,SQL示例如下:select c1,c2 from tab1 where c1=3 and time >='2010-01-01 00:00:00';
此時可只通過c1進行索引,time通過內部掃描方式執行,查詢更快,返回更多有效記錄數。SQL示例如下:
/*+ no_index_columns=[tab1.time] */ select c1,c2 from tab1 where c1=3 and time>='2010-01-01 00:00:00';
Hint表示強制
time>='2010-01-01 00:00:00'
條件走掃描。在上述SQL中,計算引擎首先檢索列c1的索引,得出滿足條件
c1=3
的行集合,然后讀取每行所對應的time列數據。如果滿足time>='2010-01-01 00:00:00'
,則將該行數據加入返回結果。不等于條件通過內部掃描
例如在查詢中使用
c2<>100
,通過索引掃描時,c2<>100
無法有效過濾掉無效記錄。SQL示例如下:select c1,c2 from tab1 where c1=3 and c2<>100;
增加
no_index_columns
Hint,使不等于條件通過內部掃描執行,SQL示例如下:/*+ no_index_columns=[tab1.c2] */ select c1,c2 from tab1 where c1=3 and c2<>100;
like條件通過內部掃描
中綴或后綴查詢,例如:
like '%abc'
或like '%abc%'
。增加
no_index_columns
Hint,使like條件通過內部掃描執行,更加快速地查詢有效記錄,SQL示例如下:/*+ no_index_columns=[tab1.c3] */ select c1,c2 from tab1 where c1=3 and c3 like '%abc%';
索引失效
索引失效時,SQL語句直接以掃描的方式進行查詢,如果表記錄數非常大,會導致查詢緩慢。
以下情形容易引起索引失效:
函數轉換(列)。
類型轉換。
like條件,例如:
like '%abc%'
。
SQL示例:
以下SQL中的函數轉換導致索引失效。time為timestamp類型,存儲時間
2017-12-10 10:00:23
。select c1,c2 from tab1 where substr(cast(time as varchar),1,10)='2017-12-10';
正確SQL示例:
select c1,c2 from tab1 where time>='2017-12-10 00:00:00' and time<='2017-12-10 23:59:59';
去掉不必要的
is not null
過濾條件SQL示例:
錯誤SQL示例:
Select c1, c2 from tab1 where c1>100 and c1<1000 and c1 is not null;
刪除上述SQL中的多余條件
and c1 is not null
,優化后SQL如下:Select c1,c2 from tab1 where c1>100 and c1<1000;
多表關聯
不同多表關聯場景下,SQL優化原則不同,其中:
普通表JOIN普通表,盡量包含分區列條件。如果不包含,則盡量通過WHERE條件過濾掉多余的數據。
復制表JOIN普通表,沒有限制。
多表關聯查詢WHERE條件中,需要明確寫明每一個表的過濾條件。通常在傳統數據庫中,都是通過索引字段關聯來快速檢索數據。例如:
Select count(*) from t1 C join t2 O on C.t1_id= O.t1_id where O.t2_time between'2018-07-20 10:00:11' and '2018-09-30 10:00:11' and O.t2_amount=100;
在明確t2與t1表都有同樣的time和type過濾條件情況下,建議修改為如下SQL:
Select count(*) from t1 join t2 on t1.id=t2.id where t1.time between '2017-12-10 00:00:00' and '2017-12-10 23:59:59' and t1.type= 100 and t2.time between '2017-12-10 00:00:00' and '2017-12-10 23:59:59' and t2.type=100