为什么“ t1内部联接t2”和“ t1内部联接t3”很快,但是“ t1内部联接t2内部联接t3”慢了265倍?

时间:2019-09-07 08:25:13

标签: mysql

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

char message [] = "apples are better than bananas...But good as grapes?";

char *delimiter_location = strstr(message, "...");
int m1_strlen            = delimiter_location - message;

// Not every C standard and every compiler supports dynamically sized arrays.
// In those cases you need to use malloc() and free().
// Or even better: strdup() or strndup().
char message_1[m1_strlen + 1];
// NB no need to call memset() because the space is written to immediately:
strncpy(message_1, message, m1_strlen);
message_1[m1_strlen] = '\0'; // This ensures a terminated string.

printf("message: %s\n", message);
printf("message 1: %s\n", message_1);
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;

花费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, 
        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

但是当我运行t1内部联接t2内部联接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
    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

问题的原因是什么?

1 个答案:

答案 0 :(得分:0)

您的问题是您的表缺少索引。要使连接正常运行,需要连接键上的索引。对于第一个查询,由MySQL保存,MySQL会在存储子查询结果的临时表上自动创建索引(auto_key0)。查询2的查询计划使我感到惊讶。我原本期望与查询1类似的计划,但我不明白所示计划的执行情况和报告方式如何。另外,我不明白为什么您在第三个查询中没有获得auto_key。

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