MySQL 9.0 發行說明
列建構子允許同時比較多個值。例如,這兩個陳述式在語義上是等效的
SELECT * FROM t1 WHERE (column1,column2) = (1,1);
SELECT * FROM t1 WHERE column1 = 1 AND column2 = 1;
此外,最佳化器會以相同的方式處理這兩個運算式。
如果列建構子資料行未涵蓋索引的前綴,則最佳化器不太可能使用可用的索引。考量以下資料表,其在 (c1, c2, c3)
上具有主鍵
CREATE TABLE t1 (
c1 INT, c2 INT, c3 INT, c4 CHAR(100),
PRIMARY KEY(c1,c2,c3)
);
在此查詢中,WHERE
子句使用索引中的所有資料行。但是,列建構子本身並未涵蓋索引前綴,導致最佳化器僅使用 c1
(key_len=4
,c1
的大小)
mysql> EXPLAIN SELECT * FROM t1
WHERE c1=1 AND (c2,c3) > (1,1)\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t1
partitions: NULL
type: ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: const
rows: 3
filtered: 100.00
Extra: Using where
在這種情況下,使用等效的非建構子運算式重寫列建構子運算式可能會導致更完整的索引使用。對於給定的查詢,列建構子和等效的非建構子運算式為
(c2,c3) > (1,1)
c2 > 1 OR ((c2 = 1) AND (c3 > 1))
重寫查詢以使用非建構子運算式會導致最佳化器使用索引中的所有三個資料行 (key_len=12
)
mysql> EXPLAIN SELECT * FROM t1
WHERE c1 = 1 AND (c2 > 1 OR ((c2 = 1) AND (c3 > 1)))\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t1
partitions: NULL
type: range
possible_keys: PRIMARY
key: PRIMARY
key_len: 12
ref: NULL
rows: 3
filtered: 100.00
Extra: Using where
因此,為了獲得更好的結果,請避免將列建構子與 AND
/OR
運算式混合使用。請使用其中一種。
在某些條件下,最佳化器可以將範圍存取方法套用至具有列建構子引數的 IN()
運算式。請參閱 列建構子運算式的範圍最佳化。