Mysql选择索引列减速大表

时间:2011-06-06 06:35:04

标签: mysql select join indexing slowdown

我有两个表: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秒)

7 个答案:

答案 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。