Tux*_*xie 6 mysql select google-cloud-sql
我们遇到了一个小故障,导致设备产生了意外数量的数据。我们的代码最终沿着 SELEXT * from XXX WHERE yyy IN (xxx,xxx,xxx....,xxxx) 的行创建一个选择查询,这应该获取过去 5 天的数据,这通常根本不是问题,因为WHERE 字段已建立索引。
我们突然开始出现大量缓慢的查询并使服务器陷入困境。在我们中止查询之前,查询运行了大约 5000 秒。弄清楚发生了什么后发现,如果我们在 IN () 子句中有一个最多包含 33594 个参数的查询,则一切正常,查询会在 200 毫秒内完成。如果我们添加一个参数,选择似乎会永远运行。我们没有让一个无限期地运行直到它完成,所以我不确定它是否会完成,但它们似乎至少持续几个小时......
select 内的数据约为 361.04KB。我们在 Google Cloud SQL 上运行 MYSQL MYSQL_8_0_31
关于可能导致这种行为的任何想法?
我更好奇为什么会发生这种情况以了解限制是什么......
原因是因为它是一个过于复杂的谓词。该IN
子句是一堆子句的语法糖OR
。太多OR
子句或子句中太多值IN
会导致谓词过于复杂,数据库引擎无法解析并生成有效的查询计划。相反,正在生成的查询计划现在可能以低效的方式扫描整个表。
发生这种情况时没有固定的硬编码限制,并且它会因查询而异。
...更好地了解系统,从而更好地了解什么解决方法/修复是最好的。
一个子句中大约 33,000 个值IN
是一个不合理的数量。哎呀,即使是 100 个值在我看来也是不合理的,而且在我看来这样的查询设计是一种反模式。
有几种重写查询可以解决问题的主要方法:
将查询分解为具有更小的子句的查询的多个副本IN
,然后UNION
将它们重新组合在一起。不过,对于您的子句中的这么多值来说,这可能也是不现实的IN
。
将值放入某种表中,例如临时表,然后使用JOIN
要过滤的表中的 a 。这通常更有效。
在我的公司,从 MySQL 5.7 开始,我们就遇到了一个问题,即根据选项,优化器可以使用的内存有上限range_optimizer_max_mem_size
。如果列表中的项目太多,优化器会放弃,并决定进行表扫描而不是使用索引。
请参阅https://dev.mysql.com/doc/refman/5.7/en/range-optimization.html#range-optimization-memory-use
我们的解决方案是在 my.cnf 中设置:
range_optimizer_max_mem_size=0
Run Code Online (Sandbox Code Playgroud)
这意味着优化器没有内存限制,因此开发人员需要避免列表太长而导致内存错误。但更可能使用索引。
这解决了长列表导致表扫描的每种情况下的问题。
归档时间: |
|
查看次数: |
3547 次 |
最近记录: |