全部產品
Search
文件中心

Lindorm:Lindorm SQL 常見問題

更新時間:Jun 25, 2026

使用 Lindorm SQL 查詢寬表資料或管理索引時,可能遇到報錯或查詢效能不符合預期的情況。本文針對寬表引擎,匯總常見問題的原因分析和解決方案。

說明

本文所列常見問題僅適用於寬表引擎。

查詢常見問題

  • Q:如何解決或規避低效查詢問題?

    A:如果執行查詢語句後,寬表引擎報錯 This query may be a full table scan and thus may have unpredictable performance,表示該查詢是低效查詢。

    什麼是低效查詢?低效查詢有哪些特點? 在 Lindorm 寬表引擎上,如果查詢語句中帶有過濾條件,但該過濾條件無法有效地利用已有的主鍵或索引,導致查詢時必須掃描全表,這樣的查詢被視為低效查詢。

    假設 test 表的聯合主鍵由 p1、p2、p3 三個列組成,p1 列是主鍵的第一列,查詢條件為 SELECT * FROM test WHERE p2=10;。此時查詢條件中未包含第一個主鍵列 p1,因此該查詢語句會被認定為低效查詢語句。

    由於低效查詢可能帶來效能穩定性風險,預設情況下 Lindorm 會檢測並阻止低效查詢的執行。

    查詢條件 WHERE 中的列是主鍵列或索引列,為什麼查詢還是觸發了低效查詢異常? 寬表引擎的主鍵、二級索引和 MySQL 聯合索引的匹配規則類似,均遵循最左匹配原則,即在多個列組成的聯合主鍵或索引中,系統從主鍵或索引鍵的第一列(最左側列)開始逐一與查詢條件中的列進行匹配。如果查詢條件中不包含主鍵或索引鍵的第一列,則此時查詢仍不會命中主鍵或二級索引,導致查詢仍然是低效查詢。

    假設 test 表的主鍵由 p1、p2、p3 三個列組成,p1 列是主鍵的第一列,根據最左匹配原則,查詢資料時系統將從 p1 列開始匹配。如果查詢條件中未包含 p1 列,例如 SELECT * FROM test WHERE p2<30;,此時無法匹配到主鍵第一列 p1,系統不會命中主鍵進而查詢全表資料以滿足查詢條件 p2<30

    如何規避低效查詢? 以下是業務中規避低效查詢的推薦方法:

    • 最佳化查詢條件,在 WHERE 語句中增加表的主鍵,或保證查詢條件中的列滿足最左匹配原則。

    • 修改表的主鍵設計以避免大查詢,具體參見如何設計寬表主鍵

    • 為表建立二級索引,相關操作參見二級索引

    • 如果表的多個列均存在多維檢索需求,可建立多維搜尋索引加速查詢,詳細資料參見搜尋索引

    • 在查詢語句中增加查詢最佳化的 HINT /*+ _l_allow_filtering_ */,強制寬表引擎執行低效查詢。例如 SELECT /*+ _l_allow_filtering_ */ * FROM dt WHERE nonPK=100;

    警告

    強制執行低效查詢可能帶來效能穩定性風險,請謹慎使用。

  • Q:使用 GROUP BY 查詢時報錯 The diff group keys of subPlan is over lindorm.aggregate.subplan.groupby.keys.limit=..., it may cost a lot memory so we shutdown this SubPlan

    A:GROUP BY 操作形成的分組數過多,可能消耗大量記憶體資源,從而加重執行個體負載,因此寬表引擎節流了結果集中分組數過大的查詢。

    解決方案

    • 在查詢語句中添加過濾條件,減少最終分組數。

    • 聯絡 Lindorm 支援人員(DingTalk號:s0s3eg3)調大分組數的閾值。

      警告

      調大分組數的閾值可能會影響執行個體的穩定性。

    • 針對多維查詢匹配情境,建議使用搜尋索引,詳細資料參見搜尋索引

  • Q:對開啟動態列的表執行 SELECT * 查詢報錯 Limit of this select statement is not set or exceeds config when select all columns from table with property DYNAMIC_COLUMNS=true

    A:開啟動態列的表可能包含大量的動態列,且表的 Schema 定義不固定。如果對這類表進行全表掃描,將導致 IO 消耗嚴重,加重執行個體負載。為避免高負載情況的產生,Lindorm 寬表引擎對動態列表的查詢語句進行了限制。

    解決方案:在 SELECT 語句中添加 LIMIT 子句,限制返回結果的數量。例如 SELECT * FROM test LIMIT 10;

  • Q:執行 SQL 查詢時,為什麼會報錯 Code grows beyond 64 KB

    A:Lindorm 的 SQL 引擎在執行查詢時採用了 JIT 編譯技術,會將查詢的物理計划動態產生位元組碼並編譯執行。Code grows beyond 64KB 報錯是指產生的方法函數的位元組碼大小超過了 JAVA 虛擬機器允許的上限,這可能是因為指定的 SQL 查詢語句中的個別謂詞過於冗長或複雜,導致產生的位元組碼過大無法被執行。

    解決方案:修改指定的 SQL 陳述式,簡化相關的謂詞表達。

  • Q:執行 SQL 查詢時,為什麼會報錯 The estimated memory used by the query exceeds the maximum limit

    A:SQL 引擎在處理儲存引擎返回的結果集時(例如彙總、排序、去重)通常需要消耗大量記憶體資源。由於 Lindorm SQL 主要面向線上業務情境,同一時刻可能存在大量查詢並發執行,為保證高並發情境下的查詢效率,系統對單個查詢的記憶體使用量進行了限制。當前預設限制為 8 MB,超出時會觸發記憶體溢出異常。

    解決方案

    • 最佳化查詢語句,結合索引將彙總、排序等運算元下推到儲存引擎執行,或通過最佳化過濾條件減少 SQL 引擎處理的資料量。

    • 調整單查詢記憶體限制閾值 QUERY_MAX_MEM

    詳細的診斷流程和具體操作步驟,參見如何診斷和解決特定查詢觸發的記憶體限制報錯?

  • Q:為什麼不建議在 WHERE 條件中同時使用大量 IS NULL 條件?

    A:在 Lindorm 寬表引擎中,IS NULL 需要同時相容“列存在且值為 NULL”和“列不存在或未寫入”的情況。因此,當 SQL 條件中包含多個 IS NULL 謂詞時,SQL 引擎在編譯階段可能對這些條件進行組合展開。N 個 IS NULL 條件理論上可能產生 2^N 個組合分支,導致編譯耗時和記憶體佔用明顯上升,嚴重時可能影響請求執行和執行個體穩定性。

    解決方案:避免在單條 SELECT、UPDATE、DELETE 等 SQL 中同時拼接大量 column IS NULL 條件。對於此類情境,推薦做法如下:

    • 優先通過主鍵、二級索引或搜尋索引縮小查詢範圍。

    • 如果業務需要頻繁判斷欄位是否為空白或是否存在,可在寫入側通過預設值、狀態欄位等方式顯式表達業務狀態。

    • 對於批量處理情境,建議拆分為多條條件更簡單的 SQL,或先查詢完整主鍵後按主鍵分批處理。

  • Q:執行 SQL 請求時,為什麼不建議在 WHERE 條件中使用大量 OR 條件的 AND 組合?

    問題描述:如果一條 SQL 的 WHERE 條件包括多個括弧內的 OR 條件通過 AND 串連,例如:

    SELECT * FROM orders
    WHERE (status = 1 OR status = 2)
      AND (pay_type = 'wechat' OR pay_type = 'alipay')
      AND (region = 'CN' OR region = 'US')
      AND ...;

    嵌套層級越多,風險越大。SELECT、UPDATE、DELETE 均適用。

    A:最佳化器在執行查詢前,需要將 WHERE 子句轉換為 DNF(析取範式),即“多個 AND 條件的 OR 集合”,以便為每個獨立條件選擇最優的索引訪問路徑。當遇到 (A OR B) AND (C OR D) 時,最佳化器必須應用程式指派律將其展開:

    (A or B) and (C or D) ⇒ (A and C) or (A and D) or (B and C) or (B and D)

    • 2 個括弧相乘,每個括弧內兩個分支:產生 2×2=4 個組合項。

    • 3 個括弧相乘,每個括弧內兩個分支:產生 2×2×2=8 個組合項。

    隨著括弧數和每個括弧內分支數的增加,組合項數量呈指數級增長,可能導致最佳化器編譯耗時和記憶體佔用大幅上升,嚴重時影響請求執行和執行個體穩定性。

    解決方案

    • 升級到寬表2.8.6版本以上,對上述查詢編譯展開過大有限制攔截,避免此類查詢造成執行個體記憶體壓力,影響其他業務。舊版本無攔截。

    • 控制(A OR B) AND (C OR D)類條件展開後的組合項小於2000為佳。

    • 如果確實存在多欄位、多維度檢索需求,建議結合搜尋引擎、計算引擎等能力設計查詢鏈路,並在上線前驗證執行計畫和資源消耗。

  • Q:如何診斷和解決特定查詢觸發的記憶體限制報錯?

    A:當 SQL 查詢報錯 The estimated memory used by the query exceeds the maximum limit 時,按照以下步驟診斷根本原因並選擇對應的解決方案。

    第一步:查看執行計畫

    對報錯的 SQL 陳述式執行 EXPLAIN 命令查看執行計畫,詳細資料參見解讀執行計畫

    在執行計畫中,確認彙總、排序、去重等高記憶體消耗運算元是否在 SQL 引擎中執行,或已下推到儲存引擎執行。在 SQL 引擎中執行的運算元會消耗單查詢的記憶體配額,而下推到儲存引擎執行的運算元則使用儲存引擎的資源。

    • 如果高記憶體消耗運算元在 SQL 引擎中執行,最佳化查詢是正確的解決方向(參見第二步)。

    • 如果運算元已下推且查詢已充分最佳化,可考慮調大記憶體限制(參見第三步)。

    第二步:最佳化查詢語句(推薦)

    如果高記憶體消耗運算元在 SQL 引擎中執行,可嘗試以下方式降低記憶體消耗:

    • 針對彙總運算元(GROUP BY、COUNT、SUM、AVG 等):在彙總列或分組列上建立二級索引或搜尋索引,將彙總運算元下推到儲存引擎執行。

    • 針對排序運算元(ORDER BY):確保排序列與現有索引對齊,避免在記憶體中排序。或通過增加更嚴格的 WHERE 過濾條件,在排序前減少資料集的大小。

    • 針對去重運算元(DISTINCT):對高基數列上的查詢使用搜尋索引,或添加選擇性過濾條件,減少處理的行數。

    第三步:調大記憶體限制閾值(請謹慎評估)

    如果所有運算元已下推且查詢無法進一步最佳化,可通過ALTER SYSTEM語句調整 QUERY_MAX_MEM 配置項:

    ALTER SYSTEM SET QUERY_MAX_MEM = <新的記憶體限制值(位元組)>;

    例如 ALTER SYSTEM SET QUERY_MAX_MEM = 8388608;

    如果使用的SQL版本說明低於 2.9.6.0,可聯絡 Lindorm 支援人員(DingTalk號:s0s3eg3)調大記憶體限制閾值。

    QUERY_MAX_MEM 當前的生效值可通過SHOW VARIABLES語句查詢。

    警告

    當線上應用的查詢並發度較高時,直接調大該記憶體限制的閾值可能會加重 Lindorm 的記憶體使用量負載,進而引發強制的 Full GC 等行為,從而降低整個叢集的響應能力。調大該記憶體限制前請務必充分評估。

索引與 Schema 問題

  • Q:為什麼建立二級索引時報錯 Executing job number exceed, max job number = 8

    A:一個執行個體中僅允許同時存在 8 個二級索引的構建任務。如果某一時刻二級索引的構建任務數已達 8 個,再次建立新的二級索引時,建立語句將會報錯。

    解決方案:建議避免同時建立大量二級索引。如果有大量建立的需求,聯絡 Lindorm 支援人員(DingTalk號:s0s3eg3)。

  • Q:在寬表引擎上已執行刪除列操作,為什麼重新添加同名列時會報錯 column is under deleting

    A:為避免由於資料類型等因素引發的髒資料問題,執行刪除列的操作後,寬表引擎還需要非同步清理記憶體、熱儲存和冷儲存上該列的資料。在資料全部清理完之前,系統不允許重新添加同名的新列。

    解決方案:由於資料清理由系統自行完成,可能會消耗很長時間。建議通過以下方式加速資料的清理過程,待資料清理完成之後重新添加同名列。

    假設執行了刪除列操作的表名為 dt

    -- 執行 FLUSH 操作,強制將記憶體中殘留的資料刷到儲存媒介上
    ALTER TABLE dt FLUSH;
    
    -- 執行 COMPACTION 操作,執行資料的合并和刪除
    ALTER TABLE dt COMPACT;
    • FLUSH 文法從 SQL 引擎 2.7.1 版本開始支援。查看 SQL 引擎版本的方法參見SQL版本說明

    • FLUSH 操作和 COMPACT 操作是非同步作業。語句執行成功並不代表資料清理完成,需要等待一段時間才能徹底清理完成。

    重要

    對資料量大的表執行 COMPACT 操作期間會佔用較多系統資源,不建議在業務高峰期執行。

  • Q:建立二級索引後,寫入資料時為什麼會報錯 Performing put operations with User-Defined-Timestamp in indexed column on MULTABLE_LATEST table is unsupported

    A:如果寫入時顯式指定了自訂時間戳記(例如使用 UPSERT 語句寫入資料時,通過 /*+ _l_ts */ 指定了自訂時間戳記),此時要求主表與二級索引表之間的可變性(Mutability)必須為 MUTABLE_ALL。但出於效能考慮,Lindorm 系統預設將主表與索引表的可變性配置為 MUTABLE_LATEST,在這種配置下建立二級索引並啟用會觸發可變性約束限制,導致報錯。

    解決方案:由於建立索引表後 MUTABILITY 參數的值不支援修改,因此需要先刪除原有的二級索引。

    • 刪除主表中原有的二級索引。

    -- 禁用原有二級索引
    ALTER INDEX IF EXISTS <原有二級索引名> ON <主表名> DISABLED;
    
    -- 刪除原有二級索引
    DROP INDEX IF EXISTS <原有二級索引名> ON <主表名>;

    DROP INDEX 文法的詳細說明參見刪除二級索引

    • 將主表的 MUTABILITY 屬性的值修改為 MUTABLE_ALL

    ALTER TABLE IF EXISTS <主表名> SET MUTABILITY='MUTABLE_ALL';

大量操作