5

我有两个表:A - 301 列(第一个名为 a1 int(11) 主键,第 2 到第 301 - double(15,11))和 B - 33 列(第一个 - b1 int(11) 唯一键,第二个一 - b2 varchar(100) 主键, ... , 33rd - b33 int(11) MUL )。

A 和 B 都有 ~ 13,500,000 条记录。

我的 mysql 查询:对于 pos 的每个值,设置中的 pos (1, 1000, 2000, ..., 13500000) 是 1000 的倍数:

select A.*, b2, b5, b7, b8, b10, b13, b33 from A join B on a1=b1 where b33 >= pos and b33 < pos+1000;

对于 b33 <= 600,000 的值,查询需要 1-5 秒。之后,查询开始需要 20-30 秒。当 b33 >= 8,000,000 时,查询开始需要 60-70 秒。我不明白为什么会出现放缓。b33 已编入索引,连接发生在一个表中定义为主键且在另一个表中唯一的键上。有解决方法吗?这确实妨碍了代码的速度,如果没有其他方法,我将不得不将表 A 和 B 拆分为几个较小的表。我真的希望我不必那样做!请帮忙!

编辑:这是解释的 o/p -

** * ** * ** * ** * * 1. row * ** * ** * ** * ** *
id: 1
select_type: SIMPLE
table: B
type: range
possible_keys: b1,b33
key: b33
key_len : 4
ref: NULL
rows: 981
Extra: 使用 where
* ** * ** * ** * ** * 2. row * ** * ** * *** ** *
id: 1
select_type: SIMPLE
table: A
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: DBName.B.b1
rows: 1
Extra:
2 rows in set (0.00 sec)

4

7 回答 7

1

由于您的数据库有几百万条记录,您是否正在采取任何措施来保持数据库的健康?

如果您的数据经常更改(可能是大量插入?),则每晚运行以下命令可能有助于提高一般响应能力:

mysqlcheck --check --analyze --auto-repair --all-databases --silent

虽然我建议在运行命令之前先阅读一下 mysqlcheck,这样你才能知道它在做什么。

您还应该考虑优化您的 InnoDB 配置,尤其是innodb_buffer_pool_size(您可以提供的内存越多越好)。在类似大小的表中,我在基于日期的字段(当然,我们立即索引)上遇到了类似的缓慢,并且将缓冲池大小从默认的 8 MB 增加到几 GB 产生了非常明显的差异。

如果您要从连接中涉及的任何表中删除许多行,您也可以考虑运行OPTIMIZE TABLE

于 2011-08-10T06:19:53.657 回答
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)
;

警告

此重构查询的目标是使查询计划中的临时表尽可能小。事实上,子查询 BBB 在任何给定时间都不应该超过 1000 行

试试看 !!!

于 2011-07-12T21:51:20.357 回答
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 版本支持,先使用 inlinew 视图进行过滤:

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 ;

第四(应该是第一个),做一个解释计划,并尝试通过比较快速查询和慢查询来了解为什么查询很慢。

祝你好运!!

于 2011-06-06T08:10:17.840 回答
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 后的索引不再适合内存,并且进行了更多的磁盘寻道

于 2011-07-12T21:33:37.690 回答
0

只是在黑暗中拍摄...

select A.*, b2, b5, b7, b8, b10, b13, b33 
  from A join B 
  on a1=b1 
  where b33 BETWEEN pos AND pos+999;
于 2011-06-06T08:22:13.547 回答
0

耶莎129p,

尝试将 b33 约束移动到连接子句中。听起来优化器只应用了一个 b33 约束 pre-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。

于 2011-07-27T21:37:07.997 回答
0

你能告诉我们你在 B 上设置的索引吗?(感兴趣的是如何定义 b33 上的索引,以及它是在单个列上定义的,还是在多个列上定义的):

SHOW INDEXES FROM B;

当您仅从 B 中选择时,您是否看到相同的速度下降?

IE

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)。

于 2011-07-12T20:58:52.127 回答