在phpMyAdmin中分析JOIN和子查询查询

时间:2018-11-05 18:22:28

标签: mysql phpmyadmin subquery left-join profiling

问题描述 我有一个审核表,其中包含某些对象的历史记录更改。审核包含唯一的审核事件ID,更改的对象的ID,更改的日期,更改的属性以及更改前后的值以及其他列。

我需要做的是查询审计数据,并获取同一对象先前更改同一字段的日期。因此,我需要再次查看审核,并为每个审核条目添加前一个类似条目,并将其日期作为上次更改日期。

架构和数据 表模式以id(id)作为主键,并以object id(parent_id)作为索引。没有其他索引。在我的测试用例中,我大约有150个对象,其中包含约80k个审核条目。

解决方案 有两个明显的解决方案子查询和左联接。

在左联接中,我基本上使用联接语句再次将同一审计表自身联接在一起,以确保对象,字段和值的更改是对应的,更改早于当前更改,并选择最大更改日期,最后仅更改为提取一个最新的先前更改,我将其按ID分组。如果没有发现以前的更改,请使用对象本身的创建日期。 左联接SQL

SELECT `audit`.`id` AS `id`,
`audit`.`parent_id` AS `parent_id`,
`audit`.`date_created` AS `date_created`,
COALESCE(MAX(`audit_prev`.`date_created`), `audit_parent`.`date_entered`) AS `date_created_before`,
`audit`.`field_name` AS `field_name`,
`audit`.`before_value_string` AS `before_value_string`,
`audit`.`after_value_string` AS `after_value_string`
FROM `opportunities_audit` `audit`
LEFT JOIN `opportunities_audit` `audit_prev`
    ON(`audit`.`parent_id` = `audit_prev`.`parent_id`
        AND `audit_prev`.`date_created` < `audit`.`date_created`
        AND `audit_prev`.`after_value_string` = `audit`.`before_value_string`
        AND `audit`.`field_name` = `audit_prev`.`field_name`)
LEFT JOIN `opportunities` `audit_parent` ON(`audit`.`parent_id` = `audit_parent`.`id`)
GROUP BY `audit`.`id`;

子查询逻辑非常相似,但是分组并使用MAX函数,我只是按日期DESC和LIMIT 1排序

SELECT `audit`.`id` AS `id`,
`audit`.`parent_id` AS `parent_id`,
`audit`.`date_created` AS `date_created`,
COALESCE((SELECT `audit_prev`.`date_created`
    FROM `opportunities_audit` AS `audit_prev`
    WHERE
        (`audit_prev`.`parent_id` = `audit`.`parent_id`)
        AND (`audit_prev`.`date_created` < `audit`.`date_created`)
        AND (`audit_prev`.`after_value_string` = `audit`.`before_value_string`)
        AND (`audit_prev`.`field_name` = `audit`.`field_name` )
        ORDER BY `date_created` DESC
    LIMIT 1
), `audit_parent`.`date_entered`) AS `date_created_before`,
`audit`.`field_name` AS `field_name`,
`audit`.`before_value_string` AS `before_value_string`,
`audit`.`after_value_string` AS `after_value_string`
FROM `opportunities_audit` `audit`
LEFT JOIN `opportunities` `audit_parent` ON(`audit`.`parent_id` = `audit_parent`.`id`);

两个查询都产生相同的结果集。

问题 当我在phpMyAdmin中运行查询时,带有join的解决方案大约需要2m30s才能返回结果。但是,phpMyAdmin表示查询花费了0.04秒。当我运行子查询解决方案时,结果立即返回,并且phpMyAdmin报告的执行时间约为0.06秒。

因此,我很难理解实际执行时间的差异是从哪里来的。我最初的猜测是该问题与返回数据集上的phpMyAdmin的自动LIMITS有关-虽然结果有80k行,但仅显示25。但是手动将LIMIT添加到查询中会使它们都快速执行。

还可以从命令行mysql工具运行查询,返回两个查询的完整结果集,并且报告的执行时间与实际执行时间相对应,并且使用联接的方法仍然比子查询快大约1.5倍。

从探查器数据看来,大部分等待时间都用于发送数据。发送数据需要花费几分钟的时间,而其他所有信息都需要数微秒的时间。

在两个查询的情况下,为什么phpMyAdmin的行为会有如此大的差异?

0 个答案:

没有答案