MySQL慢速连接 - 但并非总是而且并非在所有表上

时间:2010-06-23 08:24:15

标签: mysql join performance indexing

我们遇到了一个MySQL数据库的性能问题,这很奇怪我们需要另一组眼睛来告诉我们我们是否疯了。 我们团队中有2位MySQL认证开发人员,但他们只能说:“这是不可能的”。

无论如何,这是情况:我们有一个理论上应该合理快速的查询,但实际上是缓慢的。如果我们通过删除1个连接来减少查询,则查询变得非常快。如果我们删除不同的连接,它仍然非常慢,尽管连接表具有几乎相同的结构。更糟糕的是:连接有时很快,有时候不是......它似乎是某种随机问题,虽然它与服务器负载无关,因为我也在我的本地系统上。

表结构如下所示:

Table : article Rows : 57491
Field            Type                 Null   Key     Default     Extra
arti_id          int(10) unsigned     NO     PRI                 auto_increment
prev_id          int(10) unsigned     YES    MUL                 (null)
news_id          int(10) unsigned     NO     MUL                 (null)
cate_id          int(10) unsigned     NO     MUL                 (null)
pdf_id           int(10) unsigned     YES    MUL                 (null)
imag_id          int(10) unsigned     YES    MUL                 (null)
publication_date date                 NO     MUL                 (null)
title            varchar(255)         NO     MUL                 (null)
full_text        text                 YES    (null)              (null)

Table : category Rows : 3
Field            Type                 Null   Key     Default     Extra
cate_id          int(10) unsigned     NO     PRI                 auto_increment
code             varchar(7)           NO     (null)              (null)

Table : language Rows : 4
Field            Type                 Null     Key     Default     Extra
lang_id          int(10) unsigned     NO       PRI                 auto_increment
code             varchar(2)           NO       (null)              (null)

Table : newspaper Rows : 393
Field            Type                 Null     Key     Default     Extra
news_id          int(10) unsigned     NO       PRI                 auto_increment
lang_id          int(10) unsigned     NO       MUL                 (null)
name             varchar(255)         NO       UNI                 (null)

现在出现了奇怪的部分:你可以看到046_newspaper和046_category都有一个主键(幸运的是)。它们都是通过外键从a046_article引用的。当我们运行以下查询时:

SELECT SQL_NO_CACHE
    article.*
FROM
    article
        INNER JOIN
        newspaper AS `n`
        ON
        article.news_id = n.news_id
ORDER BY
    article.publication_date DESC
LIMIT
    50

我们在0.016秒后得到一个结果,这非常快。

现在,当我们通过类别:

的联接替换报纸的连接时
SELECT SQL_NO_CACHE
    article.*
FROM
    article
        INNER JOIN
        category AS `c`
        ON
        article.cate_id = c.cate_id
ORDER BY
    article.publication_date DESC
LIMIT
    50

查询需要1.02秒。

奇怪的是,事情并非总是如此。有时,由于没有明显的原因,第一个查询也需要很长时间。

最后我们要做的是:

SELECT SQL_CALC_FOUND_ROWS
    *,
    `n`.`name` AS `news_name`,
    `c`.`cate_id`,
    `c`.`code` AS `cate_name`,
    `l`.`code` AS `lang_name`
FROM
    `article`
        INNER JOIN
        `newspaper` AS `n`
        ON
        article.news_id = n.news_id
            INNER JOIN
            `category` AS `c`
            ON
            article.cate_id = c.cate_id
                INNER JOIN
                `language` AS `l`
                ON
                n.lang_id = l.lang_id
ORDER BY
    `article`.`publication_date` DESC
LIMIT
  50

此时需要12秒。这部分是由于*,我们可以用单个字段替换,但是它仍然需要3秒钟。

我们尝试了很多方面: - 添加索引(虽然已经存在所有必需的索引,但添加更多只是一个坏主意) - 增加排序缓冲区大小和密钥缓冲区 - 看着解释很多...... - 一遍又一遍地阅读MySQL手册 - 阅读很多论坛 然而,这样的事情并没有解决这个问题。

如果有人有任何想法,请随时大喊!如果您需要SQL脚本甚至可以访问数据库,那么您可以尝试一下,让我知道......我们的客户对这些慢页面抱怨很多......

谢谢!

3 个答案:

答案 0 :(得分:0)

  1. 始终使用EXPLAIN(QUERY)来分析和理解MySQL如何解析您的查询。
  2. 检查你的INDEX,MySQL正在为select选择错误的索引。
  3. 尝试使用SELECT和INDEX提示。 http://dev.mysql.com/doc/refman/5.1/en/index-hints.html

    SELECT * FROM table1 USE INDEX(col1_index,col2_index) 其中col1 = 1 AND col2 = 2 AND col3 = 3;

    SELECT * FROM table1 IGNORE INDEX(col3_index) 其中col1 = 1 AND col2 = 2 AND col3 = 3;

答案 1 :(得分:0)

我会为所有表执行SHOW INDEX ON表,并检查基数列是否正确(即没有NULL)。或者您可以在每张桌子上进行分析以获得良好的测量结果。由于那里有2位经过认证的MySQL开发人员,您可能已经这样做了。

下一步是查看EXPLAIN并了解MySQL如何优化它。您可能需要使用FORCE,USE或IGNORE才能使其正确优化。自MySQL和具有缓存数据(即索引)的操作系统以来,速度会有所不同,但是当您指定“无缓存”时,速度将不同。你可以发布解释吗?

答案 2 :(得分:0)

我认为您可以尝试使用标量查询。