文件首頁
MySQL 9.0 參考手冊
相關文件 下載本手冊
PDF (美式信紙) - 40.0Mb
PDF (A4) - 40.1Mb
Man Pages (TGZ) - 258.2Kb
Man Pages (Zip) - 365.3Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 9.0 參考手冊  /  ...  /  常數摺疊最佳化

10.2.1.14 常數摺疊最佳化

常數與資料行值之間的比較,其中常數值相對於資料行類型超出範圍或類型錯誤,現在在查詢最佳化期間處理一次,而不是在執行期間逐列處理。可以以此方式處理的比較是 >>=<<=<>/!==<=>

請考慮以下陳述式建立的資料表

CREATE TABLE t (c TINYINT UNSIGNED NOT NULL);

查詢 SELECT * FROM t WHERE c < 256 中的 WHERE 條件包含整數常數 256,該常數對於 TINYINT UNSIGNED 資料行來說超出範圍。先前,這是透過將兩個運算元都視為較大的類型來處理,但現在,由於 c 的任何允許值都小於常數,因此 WHERE 表達式可以改為摺疊為 WHERE 1,因此查詢會改寫為 SELECT * FROM t WHERE 1

這使得最佳化工具可以完全移除 WHERE 表達式。如果資料行 c 可為 Null (也就是說,僅定義為 TINYINT UNSIGNED),則查詢會像這樣改寫

SELECT * FROM t WHERE ti IS NOT NULL

對於與支援的 MySQL 資料行類型比較的常數,會執行如下的摺疊

  • 整數資料行類型。  整數類型與以下類型的常數進行比較,如此處所述

    • 整數值。  如果常數超出資料行類型的範圍,則比較會摺疊為 1IS NOT NULL,如已顯示的。

      如果常數是範圍邊界,則比較會摺疊為 =。例如 (使用與已定義的相同資料表)

      mysql> EXPLAIN SELECT * FROM t WHERE c >= 255;
      *************************** 1. row ***************************
                 id: 1
        select_type: SIMPLE
              table: t
         partitions: NULL
               type: ALL
      possible_keys: NULL
                key: NULL
            key_len: NULL
                ref: NULL
               rows: 5
           filtered: 20.00
              Extra: Using where
      1 row in set, 1 warning (0.00 sec)
      
      mysql> SHOW WARNINGS;
      *************************** 1. row ***************************
        Level: Note
         Code: 1003
      Message: /* select#1 */ select `test`.`t`.`ti` AS `ti` from `test`.`t` where (`test`.`t`.`ti` = 255)
      1 row in set (0.00 sec)
    • 浮點或定點數值。 如果常數是十進位類型之一(例如 DECIMALREALDOUBLEFLOAT)並且具有非零的小數部分,則它不能相等;因此進行折疊。對於其他比較,根據符號向上或向下捨入為整數值,然後執行範圍檢查,並按照已描述的整數-整數比較方式處理。

      一個太小而無法表示為 DECIMALREAL 值,會根據符號捨入為 .01 或 -.01,然後作為 DECIMAL 處理。

    • 字串類型。 嘗試將字串值解釋為整數類型,然後將比較處理為整數值之間的比較。如果失敗,則嘗試將該值作為 REAL 處理。

  • DECIMAL 或 REAL 欄位。 十進位類型與下列類型的常數進行比較,如下所述

    • 整數值。 針對欄位值的整數部分執行範圍檢查。如果沒有產生折疊結果,則將常數轉換為具有與欄位值相同小數位數的 DECIMAL,然後作為 DECIMAL 檢查(請參閱下一個)。

    • DECIMAL 或 REAL 值。 檢查溢位(也就是說,常數的整數部分中的位數是否超出欄位的十進位類型所允許的範圍)。如果是,則折疊。

      如果常數的小數部分有效位數多於欄位類型,則截斷常數。如果比較運算子是 =<>,則折疊。如果運算子是 >=<=,則因截斷而調整運算子。例如,如果欄位的類型是 DECIMAL(3,1),則 SELECT * FROM t WHERE f >= 10.13 會變成 SELECT * FROM t WHERE f > 10.1

      如果常數的小數位數少於欄位的類型,則將其轉換為具有相同位數的常數。對於 REAL 值的下溢(也就是說,小數部分位數太少而無法表示它),將常數轉換為十進位 0。

    • 字串值。 如果該值可以解釋為整數類型,則將其作為整數類型處理。否則,嘗試將其作為 REAL 處理。

  • FLOAT 或 DOUBLE 欄位。 FLOAT(m,n)DOUBLE(m,n) 值與常數進行比較時,處理方式如下

    如果該值超出欄位的範圍,則折疊。

    如果該值的小數部分超過 n 位,則截斷,並在折疊期間進行補償。對於 =<> 比較,按照先前所述折疊為 TRUEFALSEIS [NOT] NULL;對於其他運算子,則調整運算子。

    如果該值的整數位數超過 m 位,則折疊。

限制。 在下列情況下,無法使用此最佳化

  1. 使用 BETWEENIN 進行比較時。

  2. 使用 BIT 欄位或使用日期或時間類型的欄位時。

  3. 在預備語句的準備階段期間,儘管它可以在實際執行預備語句時的最佳化階段應用。這是由於在語句準備期間,常數的值尚未知。