【问题标题】:mysql - query length limitationmysql - 查询长度限制
【发布时间】:2019-12-14 21:37:47
【问题描述】:

我有一些查询,它的文本非常大。

SELECT id FROM my_table WHERE name IN ('name1','name2',...)
  • 每个名称约为 100 个字符。
  • 表包含10M行,
  • 字段名称已编入索引。

我注意到,超过某个阈值,比如 26K,性能下降,查询速度慢了约 10 倍。

例如:

25K 个名字耗时 0.27 秒

26K 个名字耗时 3.19 秒

查询长度(即sql文本本身)是否有任何限制? 还有什么?

【问题讨论】:

  • 速度表现可能是硬件问题?你检查内存使用了吗?如果内存达到 100% ,计算机可以切换到硬盘上的虚拟内存,这会超级慢
  • IN 子句的结果来自外部查询???
  • 为什么不创建一个包含 IN() 中所有名称的索引列的表,然后将其连接到您的第一个表?
  • @scaisEdge 不,来自外源。
  • @Strawberry 是用户提供的动态列表

标签: mysql sql optimization


【解决方案1】:

IN子句内容有限制

The number of values in the IN list is limited by the max_allowed_packet value.

https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_max_allowed_packet

但为了提高性能,您也可以尝试使用子查询而不是 IN 子句

SELECT id 
FROM my_table m
INNER JOIN  (
  select name 
  from my_table_temp
) t ON t.name  = m.name 

如果 IN 子句中 name 的值是从外部源获取的,请尝试评估将这个结果存储在临时表中的可能性,并在 JOIN 中使用这个临时表

或者如果外部名称很少......你可以构建一个子查询作为联合

select 'name1' name
union 
select  'name2' 
....

然后

SELECT id 
FROM my_table m
INNER JOIN  (    
  select 'name1' name
  union 
  select  'name2' 
) t ON t.name  = m.name 

【讨论】:

  • 这几乎可以肯定是正确的方法,但在 OP 的情况下,他需要先构建一个临时表,其中包含用户的值,然后将其用于约束。
  • 但是为什么是子查询呢?
  • @scaisEdge 我的数据库中 max_allowed_pa​​cket 值的值为 104857600 (100MB),而当 sql 字符串 > 1MB 时我的查询开始变慢
  • 查询变慢是因为 IN 子句是多个 OR 子句。 ..为此,我建议您评估一个内部联接..它作为一个单一的联接(而不是几个或选择)在名称列上具有适当的索引,这应该保持性能..而不会降级..
  • @mclafee - net_buffer_length 的值是多少?
【解决方案2】:

基本上有两种方法可以运行这个查询:

  1. 使用名称索引并使用索引查找列表中的每个名称。
  2. 扫描表格并查找列表中的每个名称,而不是使用索引。

MySQL 实际上优化了第二种方法,通过对名称列表进行排序。您应该检查两个查询的查询计划,以验证是否正在使用索引。

MySQL 必须决定哪种方式更好。它使用统计数据和其他可用信息来做到这一点。您观察到的是,对于本示例,这两种方法之间的截止点可能并不完全正确。

如果是这种情况,您可以使用 USE INDEX 提示来确保 MySQL 使用索引,即使 IN 列表很长。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-06
    • 2010-09-10
    • 2014-10-27
    • 2010-09-25
    • 1970-01-01
    • 1970-01-01
    • 2010-09-14
    相关资源
    最近更新 更多