MySQL支持对生成的列进行索引。例如:
生成的列gc定义为表达式f1+1。该列也被索引,优化器可以在执行计划构建过程中考虑该索引。在以下查询中,WHERE子句引用gc,优化器考虑该列上的索引是否会产生更有效的计划:
优化器可以在生成的列上使用索引来生成执行计划,即使在查询中没有按名称直接引用这些列的情况下也是如此。如果WHERE、ORDER BY或GROUP BY子句引用的表达式与某个索引生成列的定义匹配,则会发生这种情况。以下查询不直接引用gc,但确实使用了与gc定义匹配的表达式:
优化器识别出表达式f1+1与gc的定义匹配,并且gc已被索引,因此它在执行计划构建过程中会考虑该索引。您可以使用EXPLAIN看到这一点:
实际上,优化器已将表达式f1+1替换为与表达式匹配的生成列的名称。这在SHOW WARNINGS显示的扩展EXPLAIN信息中提供的重写查询中也很明显:
以下限制和条件适用于优化器对生成的列索引的使用:
为了使查询表达式与生成的列定义匹配,该表达式必须相同,并且必须具有相同的结果类型。例如,如果生成的列表达式是f1+1,如果查询使用1+f1,或者如果将f1+1(整数表达式)与字符串进行比较,优化器将无法识别匹配。
优化适用于这些运算符:=、<、<=、>、>=、BETWEEN和IN()。
对于BETWEEN和IN()以外的运算符,任何一个操作数都可以被匹配的生成列替换。对于BETWEEN和IN(),只有第一个参数可以被匹配的生成列替换,其他参数必须具有相同的结果类型。BETWEEN和IN()尚不支持涉及JSON值的比较。
生成的列必须定义为至少包含一个函数调用或前一项中提到的运算符之一的表达式。表达式不能包含对另一列的简单引用。例如,gc INT AS(f1)STORED仅包含一个列引用,因此不考虑gc上的索引。
为了将字符串与从返回引号字符串的JSON函数计算值的索引生成列进行比较,需要在列定义中使用JSON_UNQUOTE()来删除函数值中的额外引号。(对于字符串与函数结果的直接比较,JSON比较器会处理引号删除,但索引查找不会发生这种情况。)例如,与其编写这样的列定义:
这样写:
使用后一种定义,优化器可以检测到这两种比较的匹配:
如果列定义中没有JSON_UNQUOTE(),优化器只会检测到第一个比较的匹配。
如果优化器未能选择所需的索引,则可以使用索引提示迫使优化器做出不同的选择。