天天看點

[Phoenix] 十一、查詢計劃詳解一、概要二、查詢計劃三、查詢計劃詳解四、API通路查詢計劃資訊五、注意事項References

一、概要

在資料庫中,執行計劃就是表示一條SQL将要執行的步驟,這些步驟按照不同的資料庫運算符号(算子)組成,具體的組成和執行方式由資料庫中的查詢優化器來決定。換而言之,執行計劃決定了SQL的執行效率。在資料庫的使用中了解其查詢計劃的構成,是進行查詢性能調優的必要條件。本文将詳細介紹Phoenix的查詢計劃文法、組成結構,以及一些注意事項。

二、查詢計劃

1. 基本說明

在phoenix中,查詢計劃能告訴我們如下的資訊:

  • 将要掃描的CHUNK數量
  • 用戶端并發線程數量
  • 執行模式(并行或串行)
  • 查詢過濾字段或者掃描範圍
  • 将會查詢的表名
  • 估算掃描資料bytes大小(依賴stats資訊)
  • 估算掃描資料量大小(依賴stats資訊)
  • 估算數量bytes大小和資料量時間
  • 操作符被執行在用戶端或者服務端
  • 涉及的查詢operations(sort、filter, scan, merge, join, limit等)

2. 文法

explain [select... | upsert ... select | delete...]            

explain文法示例如下:

explain SELECT host FROM PTSDB WHERE host IN ('a','b');

explain UPSERT INTO t1 SELECT id FROM t2 ORDER BY K1, V1;
           

3. 如何選擇最優查詢計劃

檢查查詢計劃是否最優,核心有以下幾點可以作為參考:

  1. 盡量避免出現FULL SCAN,尤其對于不走索引表的單表查詢,不應該出現FULL SCAN
  2. 執行模式盡可能使用并行(某些情況一定是串行的執行模式)
  3. 盡可能将對應表的過濾條件或計算下推到server端
  4. 盡可能使用覆寫索引,生成不需要回查資料表的查詢計劃

三、查詢計劃詳解

1. 操作符說明

  • UNION ALL: 表示union all查詢,操作符後面接查詢計劃中涉及查詢的數量
  • AGGREGATE INTO SINGLE ROW: 沒有groupby語句情況下,聚合查詢結果到一行中。例如 count(*)
  • AGGREGATE INTO ORDERED DISTINCT ROWS:帶有group by的分組查詢
  • FILTER BY expression: 過濾出符合表達式條件的資料
  • INNER-JOIN: 多表Join
  • MERGE SORT: 進行merge sort排序,大多是用戶端對多線程查詢結果進行排序
  • RANGE SCAN: 對主鍵進行範圍掃描,通常有指定start key和stop key
  • ROUND ROBIN: 對查詢沒有排序要求,并發的在用戶端發起掃描請求。
  • SKIP SCAN: Phoenix實作的一種掃描方式,通常能比Range scan獲得更好的性能。
  • FULL SCAN: 全表掃描
  • LIMIT: 對查詢結果取TOP N
  • CLIENT: 在用戶端執行相關操作
  • X-CHUNK: 根據統計資訊可以把一個region分成多個CHUNK, X在查詢計劃中表示将要掃描的CHUNK數量,此處是多線程并發掃描的,并發的數量是由用戶端線程池的大小來決定的
  • PARALLEL X-WAY:描述了有X個并發對scan做merge sort之類的用戶端操作
  • SERIAL: 單線程串行執行
  • SERVER: 在SERVER端(RS)執行相關操作

2. 查詢計劃示例說明

分組聚合查詢。查詢計劃中有5385個并發,并行對表做範圍掃描,在server端以組合rowkey的第二列k2為過濾條件過濾,并以k2列做聚合。

explain select count(k2) from OFFSET_TEST where k2 = '3343' group by k2;
 
CLIENT 5385-CHUNK 2330168 ROWS 314572800 BYTES PARALLEL 5385-WAY RANGE SCAN OVER OFFSET_TEST [0] - [63]
SERVER FILTER BY FIRST KEY ONLY AND K2 = '3343'
SERVER AGGREGATE INTO DISTINCT ROWS BY [K2]
CLIENT MERGE SORT           

無排序查詢生成ROUND ROBIN查詢計劃。查詢計劃中有5385個并發,并行對表做ROUND ROBIN的範圍掃描,在server端以組合rowkey的第二列k2為過濾條件過濾。

explain select * from OFFSET_TEST where k2 = '3343';

CLIENT 5385-CHUNK 2330168 ROWS 314572800 BYTES PARALLEL 5385-WAY ROUND ROBIN RANGE SCAN OVER OFFSET_TEST [0] - [63] 
SERVER FILTER BY K2 = '3343'           

有排序查詢。查詢計劃中有5385個并發,并行對表做範圍掃描,在server端以組合rowkey的第二列k2為過濾條件過濾并排序,最後在用戶端進行merge sort查詢結果。

explain select * from OFFSET_TEST where k2 = '3343' order by k2;

CLIENT 5385-CHUNK 2330168 ROWS 314572800 BYTES PARALLEL 5385-WAY RANGE SCAN OVER OFFSET_TEST [0] - [63]
    SERVER FILTER BY K2 = '3343'
    SERVER SORTED BY [K2]
CLIENT MERGE SORT           

四、API通路查詢計劃資訊

String explainSql = "EXPLAIN SELECT * FROM T";
Long estimatedBytes = null;
Long estimatedRows = null;
Long estimateInfoTs = null;
try (Statement statement = conn.createStatement(explainSql)) {
        int paramIdx = 1;
        ResultSet rs = statement.executeQuery(explainSql);
        
        //列印查詢計劃
        System.out.println(QueryUtil.getExplainPlan(rs));
        
        //擷取相關估算值
        rs.next();
        estimatedBytes =
                (Long) rs.getObject(PhoenixRuntime.EXPLAIN_PLAN_ESTIMATED_BYTES_READ_COLUMN);
        estimatedRows =
                (Long) rs.getObject(PhoenixRuntime.EXPLAIN_PLAN_ESTIMATED_ROWS_READ_COLUMN);
        estimateInfoTs =
                (Long) rs.getObject(PhoenixRuntime.EXPLAIN_PLAN_ESTIMATE_INFO_TS_COLUMN);
}           

五、注意事項

  • 當有兩個以上索引表時盡量使用hint去指定查詢必須要使用的索引表,這樣可以確定即使以後再加了索引不會影響到現在使用的查詢計劃
  • 能通過資料表組合主鍵覆寫的查詢條件,盡量避免建立索引表。索引表表越多,寫放大越嚴重,維護成本也會随之增加
  • 在查詢計劃中Scan速度,SKIP SCAN > RANGE SCAN > FULL SCAN
  • 不是所有的查詢operations都能下推到server端
  • 查詢SERVER FILTER一個普通列,一般會在server端發生全表掃描操作,也需要謹慎檢查
  • 組合主鍵或者組合索引的非字首列,作為過濾條件列進行查詢時,一般會生成SCAN OVER的查詢計劃,但實際上這種查詢也很可能需要全表掃描,是以也需要根據實際情況檢查确認

References