MySQL JOIN更新执行计划疑问:shows表rows值为何为1?
数据表结构与数据
Clients表结构
+-------------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------------+--------------+------+-----+---------+-------+ | clientID | int | NO | PRI | NULL | | | name | varchar(20) | YES | | NULL | | | routine | varchar(30) | YES | | NULL | | | standardFee | decimal(5,2) | YES | | NULL | | +-------------+--------------+------+-----+---------+-------+
Shows表结构
+-------------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------------+--------------+------+-----+---------+-------+ | showID | int | NO | PRI | NULL | | | showDate | date | YES | | NULL | | | clientID | int | YES | MUL | NULL | | | attendance | int | YES | | NULL | | | ticketPrice | decimal(4,2) | YES | | NULL | | +-------------+--------------+------+-----+---------+-------+
Clients表数据
+----------+------------+------------------+-------------+ | clientID | name | routine | standardFee | +----------+------------+------------------+-------------+ | 1 | Gladys | song and dance | 140.00 | | 2 | Katherine | standup | 140.00 | | 3 | Georgeanna | standup | 140.00 | | 4 | Wanda | song and dance | 140.00 | | 5 | Ann | trained squirrel | 79.99 | +----------+------------+------------------+-------------+
Shows表数据
+--------+------------+----------+------------+-------------+ | showID | showDate | clientID | attendance | ticketPrice | +--------+------------+----------+------------+-------------+ | 1 | 2019-12-25 | 4 | 144 | 22.50 | | 2 | 2020-01-11 | 5 | 84 | 29.50 | | 3 | 2020-01-17 | 3 | 190 | 19.49 | | 4 | 2020-01-31 | 5 | 234 | 14.99 | | 5 | 2020-02-08 | 1 | 86 | 25.00 | | 6 | 2020-02-14 | 3 | 122 | 59.25 | | 7 | 2020-02-15 | 2 | 101 | 26.50 | | 8 | 2020-02-27 | 2 | 186 | 19.99 | | 9 | 2020-03-06 | 4 | 222 | 45.00 | | 10 | 2020-03-07 | 5 | 250 | 8.99 | +--------+------------+----------+------------+-------------+
执行的SQL语句
EXPLAIN UPDATE clients JOIN shows USING (clientID) SET clients.routine = 'mime', shows.ticketPrice = 30 WHERE name = 'Gladys' or name = 'Ann';
疑问
MySQL返回的执行计划中,shows表的rows值为1,但实际该表中有4行(clientID为1和5的记录)被更新。已知索引原理,但仍不理解带索引的多表查询执行逻辑,想知道该执行计划中rows值的含义及不符原因。
一、执行计划中rows值的含义
MySQL执行计划里的rows列,是优化器基于表统计信息估算的、当前表需要被扫描的行数,它是优化器判断执行成本的参考值,并非最终实际被修改或返回的精确行数。
二、数值不符的原因
多表关联的估算逻辑
这条语句的执行逻辑是先从clients表筛选出符合条件的2行数据(clientID=1和5),再通过clientID关联shows表。优化器在估算shows表的rows时,是按单个关联值的平均匹配行数来计算的——它默认认为每个clientID在shows表中平均匹配1行,所以显示rows=1。但实际clientID=1对应1行,clientID=5对应3行,总共4行,这就导致估算值和实际值出现偏差。统计信息的局限性
MySQL的表统计信息是通过抽样收集的,并非实时全量统计。当表数据量较小时(比如你的shows表只有10行),抽样误差会更明显,优化器无法精准计算每个clientID对应的实际匹配行数。索引的影响
shows表的clientID是普通索引(MUL),优化器知道可以通过索引快速定位关联数据,但它不会去精确统计每个关联值对应的索引条目数量,而是用平均匹配数来估算,这也是导致偏差的原因之一。
三、优化估算准确性的方式
如果想让估算值更接近实际情况,可以执行ANALYZE TABLE shows;更新表的统计信息,之后再查看执行计划的rows值会更精准,但依然无法保证完全和实际行数一致——因为rows本质还是估算值,不是实际计数。
内容的提问来源于stack exchange,提问作者ShrihariShetty

