我们有一个简单的查询,如下所示:
SELECT a,b,c,d FROM table WHERE a=1 and b IN ('aaa', 'bbb', 'ccc', ...)
IN子句中没有任何连接,5000个辅助值。
现在,此查询需要1-20秒才能在非常强大的(16核心)服务器上运行。该表在(a,b)上有一个索引,我们也尝试将索引反转为(b,a)。服务器有大量的内存,没有人写这个表 - 只有5个进程运行选择,如上所述。
我们做了一些分析,发现有些查询在“JOIN :: optimize”(。\ sql_select.cc 977)中花了3.5秒。我提醒你,查询根本不使用连接。
在无连接表上优化连接所花费的大量时间可能是什么原因?
以下是EXPLAIN SELECT的结果:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE table range IX_A_B IX_A_B 65 \N 5000 Using where
答案 0 :(得分:5)
尝试将5000个值放在临时表中:
declare @t table (b varchar(10))
insert into b select 'aaa'
union all select 'bbb'
union all select 'c'
....
select table.*
from table
join @t t on table.b = t.b
where table.a = 1
答案 1 :(得分:2)
b IN(x,y,...)被翻译成:(b = x OR b = y OR b = ...)
这意味着你要对表中的每个值进行5000次if-check。
答案 2 :(得分:1)
您是否在字段a上有索引,尤其是b?
如果您在优化SQL中寻求帮助,则应附加
EXPLAIN SELECT a,b,c,d FROM table WHERE a=1 and b IN ('aaa', 'bbb', 'ccc', ...)
同样,没有它,人们只能猜测。
答案 3 :(得分:1)
使用像这样的IN子句也可以是一个连接,所以它不是完全无连接的。
你在(a,b)上有一个索引是相当不错的,但是你必须想知道它是如何得到值c和d ...最后,它可能会忽略索引和只是扫描整个桌子。
尝试在(a,b, c,d )上创建索引,以便索引包含您需要的所有数据。在SQL Server中,您可以使用包含的列来执行此操作,但我认为在mysql中您还需要包含其他列。这应该意味着您的查询可以直接进入a = 1记录,并开始查找与列表匹配的b的记录,然后它具有所需的所有信息。
答案 4 :(得分:0)
您的回答是考虑以下两个答案中的建议:
MySql takes a long time optimizing a join-less query
MySql takes a long time optimizing a join-less query
另外,你提到b是高度选择性的;这样:
我建议您将索引中列的顺序更改为(b,a)。如果优化器可以更快地缩小结果范围,那么使用索引就会更加敏锐。 (将最具选择性的列放在索引的前面通常是一个很好的经验法则;如果你想要偏离这个原则那么很少。)
答案 5 :(得分:-1)
Our DBA发现这是reported bug。