MySQL Slow join - 但并非总是如此,也不是在所有表上

标签 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 脚本甚至访问数据库,那么您可以尝试一下,让我知道...我们的客户提示页面速度慢...

谢谢!

最佳答案

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

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

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

关于MySQL Slow join - 但并非总是如此,也不是在所有表上,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3100028/

相关文章:

mysql - 完全外连接中的 SQL 错误 1064

Swift - 高效的数字到字符转换

MySQL 临时表性能

php - 无缓冲查询错误 - 如何在本地主机上获取它们

php - SQL插入语句不起作用

php - 子查询未返回预期结果

mysql - 为每行选择 x 天的 AVG

sql - 按字段值连接 SQL 表

c - 使用通用案例进行开关改进

linux - 在 Linux 中存储和访问多达 1000 万个文件