使用多个内部join和order子句时,SQL查询非常慢

时间:2019-07-10 10:33:02

标签: mysql query-optimization

我有一个包含三个相关表的MySQL数据库, t1 6598 行, t2 1713 行和 t3 10023 行。

详细信息:

TABLE t1 (
    `id` SERIAL,
    `t2_id` BIGINT UNSIGNED NOT NULL,
    `t3_id` BIGINT UNSIGNED,
    PRIMARY KEY (`id`),
    FOREIGN KEY (t2_id) REFERENCES t2(id),
    FOREIGN KEY (t3_id) REFERENCES t3(id)   
);

TABLE t2(
    `id` SERIAL,
    `name` VARCHAR(128) NOT NULL,
    PRIMARY KEY (`id`)
);

TABLE t3 (
    `id` SERIAL,
    `name` VARCHAR(128),
    PRIMARY KEY (`id`)
);

我想执行以下查询,但是查询没有完成(基本上会永远占用):

SELECT *
FROM t1
INNER JOIN t3
ON t1.t3_id = t3.id
INNER JOIN t2
ON t1.t2_id = t2.id
WHERE (t3.name NOT NULL)
ORDER BY t3.name ASC , t1.id ASC
LIMIT 25

当我删除订单条款时,它的工作速度非常快(0.17秒)。

如何更改查询以使其正常工作?

2 个答案:

答案 0 :(得分:1)

我可以建议以下指标:

CREATE INDEX idx_t1 ON t1 (t2_id, t3_id, id);
CREATE INDEX idx_t3 ON t3 (id, name);

这些索引至少应该大大加快连接速度。如果使用MySQL,很可能会采取以下加入策略:

SELECT *
FROM t2
INNER JOIN t1
    ON t2.id = t1.t2_id
INNER JOIN t3
    ON t1.t3_id = t3.id
WHERE
    t3.name IS NOT NULL
ORDER BY
    t3.name,
    t1.id
LIMIT 25;

这里的想法是我们对t2进行全表扫描,这是迄今为止最小的表。无论如何,t2中的记录没有限制,所以我们最好先扫描一下。然后,对于t1t3的每个联接,我们尝试使用索引设置。请注意,由于表中的列相对较少,因此定义的两个索引可以轻松覆盖所有列,从而增加了MySQL选择使用索引的可能性。

答案 1 :(得分:0)

t1是一个多对多映射表。它不需要PK的替代id。相反,它需要其他两列的组合PK,再加上另一个方向的索引。

有关这些内容和其他一些提示的讨论,请参见http://mysql.rjweb.org/doc.php/index_cookbook_mysql#many_to_many_mapping_table