我有两个表:A - 301列(第一个名为a1 int(11)主键,第二个到第301个 - 双(15,11))& B - 33列(第一个 - b1个int(11)唯一键,第二个 - b2 varchar(100)主键,...,33rd - b33 int(11)MUL)。
A& A B有大约13,500,000条记录。
我的mysql查询:对于pos的每个值,在集合中的pos(1,1000,2000,...,13500000)是1000的倍数:
在a1 = b1上从A连接B中选择A. *,b2,b5,b7,b8,b10,b13,b33,其中b33> = pos且b33
对于b33< = 600,000的值,查询需要1-5秒。之后,查询开始耗时20-30秒。当b33> = 8,000,000时,查询开始花费60-70秒。我无法理解为什么减速正在发生。 b33被索引,并且连接发生在一个表中定义为primary而另一个表中唯一的键上。这有解决方法吗?这实际上阻碍了代码的速度,我将不得不拆分表格A&如果没有其他工作,B会变成几个较小的。我真的希望我不必那样做!请帮忙!
编辑:这是EXPLAIN的o / p -
的 的 ** * ** * ** * 的** * * 1.行 * ** * ** * * * * ** *
id:1
select_type:SIMPLE
表:B
类型:范围
possible_keys:b1,b33
关键:b33
key_len:4
ref:NULL
行:981
额外:使用在哪里
的 * ** * ** * ** * ** * 2.行 * ** * ** * ** * * * *
id:1
select_type:SIMPLE
表:A
输入:eq_ref
possible_keys:PRIMARY
关键:主要
key_len:4
ref:DBName.B.b1
行:1
附加:
2行(0.00秒)
答案 0 :(得分:1)
由于您的数据库有数百万条记录,您是否正在采取措施保持您的数据库健康?
如果您的数据经常更改(很多插入,可能?),那么每晚运行以下命令可能有助于提高常规响应能力:
mysqlcheck --check --analyze --auto-repair --all-databases --silent
虽然在运行命令之前我会建议reading up a bit on mysqlcheck,但是你知道它在做什么。
您还应该查看optimizing your InnoDB configuration,尤其是innodb_buffer_pool_size
(您可以提供的内存越多越好)。在类似大小的表中,我在基于日期的字段(当然,我们立即编入索引)上遇到类似的缓慢,并且将缓冲池大小从默认的8兆字节增加到几千兆字节会产生非常显着的差异。
如果您要从联接中涉及的任何表中删除许多行,您也可以考虑运行OPTIMIZE TABLE
。
答案 1 :(得分:0)
我不是MySQL(或任何东西!)大师,但我会考虑一些事情。首先,是b33均匀分布?可能会慢一点,因为它有效地检索更多行? 其次,您是否考虑过在单个查询中执行所有工作而不是13500?类似的东西:
select A.*, b2, b5, b7, b8, b10, b13, b33, (b33 - 1 DIV 1000) the_group
from A join B on a1=b1
第三,一个疯狂的猜测,如果您的MySQL版本支持它,请先使用内联视图进行过滤:
select A.*, b2, b5, b7, b8, b10, b13, b33
from A join (select b1,b2, b5, b7, b8, b10, b13, b33
from B b33 >= pos and b33 < pos+1000) B_NEW
on a1=b1 ;
第四个(应该是第一个),做一个解释计划,并尝试了解为什么查询比较快速查询和慢速查询的速度很慢。
祝你好运!!答案 2 :(得分:0)
在黑暗中一枪......
select A.*, b2, b5, b7, b8, b10, b13, b33
from A join B
on a1=b1
where b33 BETWEEN pos AND pos+999;
答案 3 :(得分:0)
您能告诉我们您在B上设置的指数吗? (感兴趣的是如何定义b33上的索引,以及它是在单个列上还是在多个列上定义的):
SHOW INDEXES FROM B;
当你只从B中选择时,你会看到相同的速度降低吗?
即
select b2, b5, b7, b8, b10, b13, b33 from B where b33 >= pos and b33 < pos+1000;
你能告诉我们SHOW CREATE TABLE
涉及字段b33的部分(对允许NULL感兴趣)
您使用MyISAM或InnoDB作为数据库引擎吗? (您可以在SHOW CREATE TABLE
)的结果中看到这一点。
答案 4 :(得分:0)
解释计划和索引似乎很好。
我建议您比较一下配置文件,看看时间到底在哪里:
SET profiling=1;
select A.*, b2, b5, b7, b8, b10, b13, b33 from A join B on a1=b1 where b33 >= 0 and b33 < 1000;
SHOW PROFILE;
select A.*, b2, b5, b7, b8, b10, b13, b33 from A join B on a1=b1 where b33 >= 1000000 and b33 < 1001000;
SHOW PROFILE;
SET profiling=0;
但我认为它可能很慢,因为索引后600k不再适合内存而且更多的磁盘搜索
答案 5 :(得分:0)
你需要重新考虑这个问题!!!
以下是您的旧查询:
select A.*, b2, b5, b7, b8, b10, b13, b33
from A join B on a1=b1 where b33 >= pos and b33 < pos+1000;
这是新的:
SELECT
AAA.*,b2,b5,b7,b8,b10,b13,b33
FROM
A AAA INNER JOIN
(
select
A.a1,b2,b5,b7,b8,b10,b13,b33
from
A INNER JOIN
(
SELECT
b1,b2,b5,b7,b8,b10,b13,b33
FROM B
WHERE
b33 >= pos and
b33 < pos+1000
) BB
ON A.a1=B.b1
) BBB
USING (a1)
;
CAVEAT
此重构查询的目标是使查询计划中的临时表尽可能小。实际上,子查询BBB在任何给定时间都不应超过1000行。
试一试!!!
答案 6 :(得分:0)
ayesha129p,
尝试将b33约束移动到join子句中。听起来好像只应用了一个b33约束之前的join-set-creation。
select A.*, b2, b5, b7, b8, b10, b13, b33 from A join B
on a1=b1 and b33 >= pos and b33 < pos+1000;
这样,优化器应该使用b33索引,并在尝试连接之前将B行设置为1000。