我在三列上有两个表之间的连接。连接需要几个小时才能完成,所以我在每个表的所有三列上添加了一个复合索引。然后,有时连接会非常快,有时它仍然会很慢。
使用EXPLAIN,我注意到当它选择使用复合索引进行连接时速度很快,而当它只在一个列上选择索引时速度很慢。但这些运行中的每一个都使用相同的数据。
SQL中是否存在随机性选择使用哪个索引?为什么会不一致?
如果有帮助:它是从python中的pandas查询的MySQL数据库。
答案 0 :(得分:1)
本身并不涉及随机性。优化器利用表和索引统计(行数和基数)以及查询中的谓词来开发估计值,例如:需要检索的行数。
MySQL还评估每个可能的访问计划的连接操作,排序操作等的成本(例如,使用哪个索引,访问表中的哪个顺序)以计算每个计划的估计成本。
然后优化器会比较成本,并使用成本最低的计划。有一些参数(MySQL系统变量)会影响成本估算。 (例如,调整I / O操作的预期成本。)
问:为什么会不一致?对于InnoDB表,收集统计信息会产生一些随机性。 InnoDB使用采样技术,进行深度潜水。进入一小组"随机"页面。这些样本页面的结果被推断为整个表格的估计值。
一些InnoDB调整参数(MySQL系统变量)影响(增加/减少)收集统计信息时采样的页数。采样较少数量的页面可能更快,但较小的样本使得样本集更可能不完全代表整个表格。使用大量样本会在一定程度上缓解这种情况,但采样时间会更长。这是一种权衡。
请注意,当使用DML操作更改表中10%的行时,InnoDB会自动重新收集统计信息。 (在某些情况下,可能无法触发自动收集统计信息,例如,创建新的(空)表并使用LOAD DATA
语句填充它,这可能导致无法收集统计信息。)
因此,观察到的行为最可能的解释是,在不同的时间,优化器可以使用不同的统计信息。
请注意,通过在SQL文本中包含提示,可以影响优化器选择使用特定索引的计划。我们通常不需要这样做,我们也不想这样做。但在某些情况下,优化者选择效率低下的计划,我们可以帮助您制定更好的计划。
一些参考资料(来自MySQL 5.7参考手册)
https://dev.mysql.com/doc/refman/5.7/en/optimizer-hints.html
https://dev.mysql.com/doc/refman/5.7/en/innodb-performance-optimizer-statistics.html