mysql - 为什么 "t1 inner join t2"和 "t1 inner join t3"快,但 "t1 inner join t2 inner join t3"慢 265 倍?

标签 mysql

我在我的 PC 上使用 bitnami WAMP 创建了一个 mysql 服务器,并使用流畅的 SQL 创建了两个表 table_a 和 table_b:

CREATE TABLE `table_a` (
  `id` int(11) DEFAULT NULL,
  `c_id` varchar(45) DEFAULT NULL,
  `date` date DEFAULT NULL,
  `value` decimal(10,2) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `table_b` (
  `id` int(11) DEFAULT NULL,
  `c_id` varchar(45) DEFAULT NULL,
  `status` int(1) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

当我运行时:

select 
    t1.id, 
    t1.date,
    t1.value
from
    (
    select 
        id,
        c_id,
        date,
        value
    from 
        table_a
    where
        id >= '7000'
    and id <  '10000'
    )
    t1
inner join
    (
    select 
        id, 
        c_id 
    from 
        table_b 
    where 
        status = 1
        id >= '7000'
    and id <  '10000'
    group by 
        id, 
        c_id
    order by null
    ) 
    t2
on 
    t1.id = t2.id
and t1.c_id = t2.c_id

花费 0.031 秒, 这是解释计划: explain plan

当我运行时:

select 
    t1.id, 
    t1.date,
    t1.value
from
    (
    select 
        id,
        c_id,
        date,
        value
    from 
        table_a
    where
        id >= '7000'
    and id <  '10000'
    )
    t1
inner join
(
    select 
        id
    from 
        (

            SELECT 
                id, 
                count(*) as times 
            FROM 
                table_b 
            where 
                status = 1
            and id >= '7000'
            and id <  '10000'   
            group by 
                id 
            order by null

        )
        t 
    where 
        times >= 2
) 
t3
on t1.id = t3.id

它仍然需要 0.031 秒, 这是解释计划: explain plan

但是当我运行 t1 inner join t2 inner join t3 时,它花费了 8.375 秒,这是 sql:

select 
    t1.id, 
    t1.date,
    t1.value
from
    (
    select 
        id,
        c_id,
        date,
        value
    from 
        table_a
    where
        id >= '7000'
    and id <  '10000'
    )
    t1
inner join
    (
    select 
        id, 
        c_id 
    from 
        table_b 
    where 
        status = 1
        id >= '7000'
    and id <  '10000'
    group by 
        id, 
        c_id
    order by null
    ) 
    t2
on 
    t1.id = t2.id
and t1.c_id = t2.c_id

inner join
(
    select 
        id
    from 
        (

            SELECT 
                id, 
                count(*) as times 
            FROM 
                table_b 
            where 
                status = 1
            and id >= '7000'
            and id <  '10000'   
            group by 
                id 
            order by null

        )
        t 
    where 
        times >= 2
) 
t3
on t1.id = t3.id

这是解释计划: explain plan

问题的原因是什么?

最佳答案

您的问题是您的表缺少索引。连接键需要一个索引才能使连接正常执行。对于第一个查询,MySQL 会自动在存储子查询结果的临时表上创建索引 (auto_key0),从而保存您。查询 2 的查询计划让我感到惊讶。我本来希望有一个与查询 1 类似的计划,但我不明白显示的计划如何像报告的那样执行。另外,我不明白为什么你在第三个查询中没有得到 auto_key。

无论如何,对于 InnoDB 表,建议始终定义一个主键。在您的情况下,我猜 id 您是表中的主键。您的查询还将受益于 c_id 上的二级索引。

关于mysql - 为什么 "t1 inner join t2"和 "t1 inner join t3"快,但 "t1 inner join t2 inner join t3"慢 265 倍?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57831990/

相关文章:

mysql - 如何通过检查另一个表来排除一些数据库记录

Mysql 事件不工作

mysql - 是否可以将 cfqueryparams 作为准备好的语句参数发送到 MySQL?

mysql - Azure MySql Rest API。插入新的防火墙规则

php - FuelPHP中连接Mysql超时

php - 用于在第 1 行的 WHERE 1=0' 附近使用正确语法的 MySQL 服务器版本

MySQL 根据主键和一列删除除一个值之外的所有值

PHP 准备语句;奇怪的结果

php - 使用 PDO 和 OOP 的 MySQL 查询问题

php - Laravel Auth 重复电子邮件