MySQL 8.3 Release Notes
行构造器允许同时比较多个值。例如,这两个语句是语义等价的:
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()
表达式。请参阅 行构造器表达式的范围优化。