全部產品
Search
文件中心

PolarDB:使用Explain判斷SQL是否可以使用列存索引

更新時間:Feb 15, 2025

本文將介紹如何使用Explain來判斷SQL語句是否能夠使用列存索引來加速查詢。

分析樣本

PolarDB MySQL版叢集中,列存執行計畫以橫向樹的形式輸出,該格式與行存執行計畫的輸出格式存在明顯區別。您可以通過使用Explain查看SQL的執行計畫,來判斷某條SQL語句是否可以使用列存索引加速功能。

SQL樣本:

EXPLAIN SELECT l_orderkey, SUM(l_extendedprice * (1 - l_discount)) AS revenue, o_orderdate, o_shippriority
FROM customer, orders, lineitem
WHERE c_mktsegment = 'BUILDING'
AND c_custkey = o_custkey
AND l_orderkey = o_orderkey
AND o_orderdate < date '1995-03-24'
AND l_shipdate > date '1995-03-24'
GROUP BY l_orderkey, o_orderdate, o_shippriority
ORDER BY revenue DESC, o_orderdate;

行存執行計畫顯示結果:

+----+-------------+----------+------------+------+--------------------+------------+---------+-----------------------------+--------+----------+----------------------------------------------+
| id | select_type | table    | partitions | type | possible_keys      | key        | key_len | ref                         | rows   | filtered | Extra                                        |
+----+-------------+----------+------------+------+--------------------+------------+---------+-----------------------------+--------+----------+----------------------------------------------+
|  1 | SIMPLE      | customer | NULL       | ALL  | PRIMARY            | NULL       | NULL    | NULL                        | 147630 |    10.00 | Using where; Using temporary; Using filesort |
|  1 | SIMPLE      | orders   | NULL       | ref  | PRIMARY,ORDERS_FK1 | ORDERS_FK1 | 4       | tpch100g.customer.C_CUSTKEY |     14 |    33.33 | Using where                                  |
|  1 | SIMPLE      | lineitem | NULL       | ref  | PRIMARY            | PRIMARY    | 4       | tpch100g.orders.O_ORDERKEY  |      4 |    33.33 | Using where                                  |
+----+-------------+----------+------------+------+--------------------+------------+---------+-----------------------------+--------+----------+----------------------------------------------+
3 rows in set, 1 warning (0.00 sec)

列存執行計畫顯示結果(橫向樹形式):

+----+----------------------------+----------+--------+--------+-----------------------------------------------------------------------------+
| ID | Operator                   | Name     | E-Rows | E-Cost | Extra Info                                                                  |
+----+----------------------------+----------+--------+--------+-----------------------------------------------------------------------------+
|  1 | Select Statement           |          |        |        | IMCI Execution Plan (max_dop = 4, max_query_mem = 858993459)                |
|  2 | └─Sort                     |          |        |        | Sort Key: revenue DESC,o_orderdate ASC                                      |
|  3 |   └─Hash Groupby           |          |        |        | Group Key: (lineitem.L_ORDERKEY, orders.O_ORDERDATE, orders.O_SHIPPRIORITY) |
|  4 |     └─Hash Join            |          |        |        | Join Cond: orders.O_ORDERKEY = lineitem.L_ORDERKEY                          |
|  5 |       ├─Hash Join          |          |        |        | Join Cond: customer.C_CUSTKEY = orders.O_CUSTKEY                            |
|  6 |       │ ├─Table Scan       | customer |        |        | Cond: (C_MKTSEGMENT = "BUILDING")                                           |
|  7 |       │ └─Table Scan       | orders   |        |        | Cond: (O_ORDERDATE < 03/24/1995)                                            |
|  8 |       └─Table Scan         | lineitem |        |        | Cond: (L_SHIPDATE > 03/24/1995)                                             |
+----+----------------------------+----------+--------+--------+-----------------------------------------------------------------------------+
8 rows in set (0.01 sec)

相關文檔

列存索引只能訪問被其所覆蓋的列。因此,當您的SQL語句中所需的表或列未被列存索引完全覆蓋時,列存索引將無法生效。

  • 檢查SQL語句中的表是否已建立列索引:預存程序dbms_imci.check_columnar_index()能夠解析輸入的SQL語句,提取該語句中使用的所有列,並驗證這些列是否被列索引所覆蓋。

  • 擷取建立列存索引的DDL語句:預存程序dbms_imci.columnar_advise()可以針對輸入的SQL語句,產生相應的用於添加列存索引的DDL語句。執行後,可以確保該SQL語句中涉及的所有列均被列索引覆蓋。

常見問題

為什麼SQL語句並沒有走列存索引?

新增唯讀列存節點後,需要為SQL語句中所查詢的表都增加列存索引,且SQL語句的預估執行代價超過一定閾值,該SQL語句才會使用列索引進行查詢。另外,SQL語句需要被轉寄到唯讀列存節點,才可以使用列存索引進行查詢加速。一般來說,如果一條SQL語句無法使用列存索引進行查詢,可以按照以下步驟進行問題排查:

  1. 確認SQL是否被轉寄至唯讀列存節點。

    • 使用的資料庫連接地址中的服務節點是否包含唯讀列存節點。

    • 通過SQL洞察功能,可以確認SQL是否被轉寄到了唯讀列存節點。具體資訊,請參見SQL洞察

    如果使用叢集地址並開啟行存/列存自動引流,同時SQL的預估執行代價高於設定的閾值loose_imci_ap_thresholdloose_cost_threshold_for_imci,則資料庫代理將會將SQL轉寄至唯讀列存節點。此外,您可以在SQL語句的SELECT關鍵字前添加HINT文法/*FORCE_IMCI_NODES*/以強制指定將SQL轉寄到唯讀列存節點。具體資訊,請參見配置自動引流閾值。樣本如下:

    核心版本8.0.1.1.39與8.0.2.2.23及之後的版本,參數loose_imci_ap_threshold被棄用,統一使用參數loose_cost_threshold_for_imci
    /*FORCE_IMCI_NODES*/EXPLAIN SELECT COUNT(*) FROM t1 WHERE t1.a > 1;
    建立一個新的資料庫連接地址,可以保證SQL語句一定會被轉寄到唯讀列存節點上執行。具體資訊,請參見建立一個新的資料庫連接地址
  2. SQL的預估執行代價是否高於設定的閾值。

    在唯讀列存節點上,最佳化器會對SQL進行執行代價預估,如果預估執行代價高於設定的閾值loose_imci_ap_thresholdloose_cost_threshold_for_imci,則使用列存索引進行查詢,否則將使用原有的行索引進行查詢。

    在確認SQL被轉寄到唯讀列存節點後,如果通過EXPLAIN查看執行計畫依然沒有使用列存索引,可以通過比較預估執行代價與預設的閾值,判斷是否是預估執行代價過小而沒有使用列存索引。您可以通過查詢Last_query_cost變數擷取“上一條SQL的預估執行代價”:

    -- 使用EXPLAIN查看SQL的執行計畫
    EXPLAIN SELECT * FROM t1;
    -- 擷取上一條SQL的預估執行代價
    SHOW STATUS LIKE 'Last_query_cost';
    如果使用叢集地址串連資料庫,建議您在SHOW STATUS LIKE 'Last_query_cost'前添加HINT文法/*ROUTE_TO_LAST_USED*/,以確保能夠在正確的節點上查詢到上一條語句的預估執行代價。例如,/*ROUTE_TO_LAST_USED*/SHOW STATUS LIKE 'Last_query_cost';

    若SQL的預估執行代價小於預設的閾值,可以考慮調整loose_imci_ap_thresholdloose_cost_threshold_for_imci的值。例如,使用HINT文法調整單條SQL的預設閾值:

    /*FORCE_IMCI_NODES*/EXPLAIN SELECT /*+ SET_VAR(cost_threshold_for_imci=0) */ COUNT(*) FROM t1 WHERE t1.a > 1;
  3. SQL中所涉及的表或列是否被列存索引完全覆蓋。

    可以通過內建的預存程序dbms_imci.check_columnar_index('<query_string>'),檢查SQL語句中的表或列是否已建立列存索引。具體資訊,請參見檢查SQL語句中的表或列是否已建立列存索引。樣本如下:

    CALL dbms_imci.check_columnar_index('SELECT COUNT(*) FROM t1 WHERE t1.a > 1');

    如果SQL未被列存索引完全覆蓋,調用該預存程序將返回未被覆蓋的表和列,您需對返回的表和列逐一建立列存索引。如果已經完全被列存索引覆蓋,則調用該預存程序將返回空結果集。

  4. 是否有不支援的SQL特性。

    通過查看列存索引文法使用限制,確認某個SQL特性是否支援列存索引。具體資訊,請參見列存索引文法使用限制

如按上述步驟排查後,SQL語句仍然沒有走列存索引,可通過專家面對面進行諮詢或聯絡我們

如何為SQL增加合適的列存索引?

建議您為SQL中所需的列添加列存索引。具體資訊,請參見檢查SQL語句中的表或列是否已建立列存索引

當一條SQL語句所需的列被列存索引完全覆蓋時,該SQL語句才能使用列存索引進行查詢。如果SQL語句中所需的列未被列存索引完全覆蓋,可以通過ALTER TABLE語句來增加列存索引。PolarDB為您提供了一系列內建預存程序以輔助此操作。

說明
  • 使用dbms_imci.columnar_advise()預存程序可以獲得某個SQL語句所需的建立列存索引DDL語句。按照這個DDL語句構建列存索引,可以保證該SQL語句完全被列存索引覆蓋。具體資訊,請參見擷取建立列存索引的DDL語句

    dbms_imci.columnar_advise('<query_string>');
  • 使用dbms_imci.columnar_advise_begin()dbms_imci.columnar_advise_end()以及dbms_imci.columnar_advise()預存程序,可以獲得一批SQL語句所需的建立列存索引DDL語句。具體資訊,請參見批量擷取建立列存索引的DDL語句