mysql - 当解释看起来不错时如何改善查询时间?

标签 mysql sql query-optimization

我有一个包含12 558 392记录的大表'placement';

当我尝试使用此表获取数据时,我遇到了性能问题(加载时间大约 5 秒)。 当我解释这个查询时,一切看起来都不错,但查询时间太长了。

我的查询示例:

    SELECT SQL_NO_CACHE om.*
    FROM order_materials om
          INNER JOIN material m ON om.material_id = m.id AND om.deleted = FALSE
          INNER JOIN placement p ON m.id = p.material_id AND m.deleted = FALSE AND p.deleted = FALSE
          INNER JOIN block b ON p.block_id = b.id AND b.deleted = FALSE
          INNER JOIN orders o ON om.order_id = o.id AND o.deleted = FALSE
          INNER JOIN product pr ON pr.mediaPlan_id = p.mediaplan_id
    WHERE
           b.advTable_id = 139
           AND p.date >= '2018-03-01 00:00:00' AND p.date <= '2018-04-01 00:00:00'
    GROUP BY om.material_id;

解释:

    +----+-------------+-------+------------+--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+---------+---------------------------+------+----------+----------------------------------------------+
    | id | select_type | table | partitions | type   | possible_keys                                                                                                                                                                                                             | key                  | key_len | ref                       | rows | filtered | Extra                                        |
    +----+-------------+-------+------------+--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+---------+---------------------------+------+----------+----------------------------------------------+
    |  1 | SIMPLE      | b     | NULL       | ref    | PRIMARY,FK597C48D47B04A3                                                                                                                                                                                                  | FK597C48D47B04A3     | 5       | const                     |  455 |    50.00 | Using where; Using temporary; Using filesort |
    |  1 | SIMPLE      | p     | NULL       | ref    | FK6ADE12E521DC3251,FK6ADE12E59B1CA2F1,FK6ADE12E5AFA9B543,date_ind,placement_b,placement_material_id_mediaplan_id_index,placement_material_id,placement_material_id_mediaplan_id_order_id_block_id_index,block_id_date_ind | FK6ADE12E521DC3251   | 5       | openmarket.b.id           |  135 |     0.82 | Using where                                  |
    |  1 | SIMPLE      | pr    | NULL       | ref    | FKED8DCCEF9B1CA2F1                                                                                                                                                                                                        | FKED8DCCEF9B1CA2F1   | 5       | openmarket.p.mediaplan_id |    1 |   100.00 | Using index                                  |
    |  1 | SIMPLE      | m     | NULL       | eq_ref | PRIMARY                                                                                                                                                                                                                   | PRIMARY              | 4       | openmarket.p.material_id  |    1 |    50.00 | Using where                                  |
    |  1 | SIMPLE      | om    | NULL       | ref    | FK_order_materials_1,FK_order_materials_2                                                                                                                                                                                 | FK_order_materials_2 | 4       | openmarket.p.material_id  |    2 |    50.00 | Using where                                  |
    |  1 | SIMPLE      | o     | NULL       | eq_ref | PRIMARY                                                                                                                                                                                                                   | PRIMARY              | 4       | openmarket.om.order_id    |    1 |    50.00 | Using where                                  |
    +----+-------------+-------+------------+--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+---------+---------------------------+------+----------+----------------------------------------------+

显示创建表order_materials:

    CREATE TABLE `order_materials` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `order_id` int(11) NOT NULL,
      `material_id` int(11) NOT NULL,
      `deleted` bit(1) NOT NULL DEFAULT b'0',
      `created_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
      `updated_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
      `last_mod_user_id` int(11) DEFAULT NULL,
      `placements_count` int(11) NOT NULL DEFAULT '0',
      PRIMARY KEY (`id`),
      KEY `FK_order_materials_1` (`order_id`),
      KEY `FK_order_materials_2` (`material_id`),
      CONSTRAINT `FK_order_materials_1` FOREIGN KEY (`order_id`) REFERENCES `orders` (`id`),
      CONSTRAINT `FK_order_materials_2` FOREIGN KEY (`material_id`) REFERENCES `material` (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=251369 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

SHOW CREATE TABLE placement;

    CREATE TABLE `placement` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `changeDate` datetime DEFAULT NULL,
      `date` datetime NOT NULL,
      `plannedPosition` tinyint(4) DEFAULT NULL,
      `realPosition` tinyint(4) DEFAULT NULL,
      `positionWithPolitics` tinyint(4) DEFAULT NULL,
      `material_id` int(11) DEFAULT NULL,
      `mediaplan_id` int(11) NOT NULL,
      `block_id` int(11) DEFAULT NULL,
      `visible` bit(1) NOT NULL,
      `blockStartTime` datetime DEFAULT NULL,
      `price` float DEFAULT NULL,
      `pricedPrice` float DEFAULT NULL,
      `actualStartTime` datetime DEFAULT NULL,
      `playedPosition` tinyint(4) DEFAULT NULL,
      `status` int(11) DEFAULT NULL,
      `played_material_id` int(11) DEFAULT NULL,
      `deleted` bit(1) NOT NULL DEFAULT b'0',
      `created_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
      `updated_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
      `last_mod_user_id` int(11) DEFAULT NULL,
      `conflict_status_lid` int(11) DEFAULT NULL COMMENT 'lookup category placement_conflict',
      `conflict_by_type_in_block` bit(1) NOT NULL DEFAULT b'0',
      `conflict_by_type_near` bit(1) NOT NULL DEFAULT b'0',
      `conflict_by_time_overflow` bit(1) NOT NULL DEFAULT b'0',
      `conflict_by_position` bit(1) NOT NULL DEFAULT b'0',
      `order_id` int(11) DEFAULT NULL,
      `order_status_lid` int(11) DEFAULT NULL,
      `play_type_lid` int(11) DEFAULT NULL,
      PRIMARY KEY (`id`),
      KEY `FK6ADE12E521DC3251` (`block_id`),
      KEY `FK6ADE12E59B1CA2F1` (`mediaplan_id`),
      KEY `FK6ADE12E5AFA9B543` (`material_id`),
      KEY `blockstarttime` (`blockStartTime`),
      KEY `date_ind` (`date`),
      KEY `bst_rp_ind` (`blockStartTime`,`realPosition`),
      KEY `status_ind` (`status`),
      KEY `FK_played_material` (`played_material_id`),
      KEY `FK_placement_1` (`conflict_status_lid`),
      KEY `FK_placement_2` (`order_id`),
      KEY `FK_placement_3` (`order_status_lid`),
      KEY `FK_placement_4` (`play_type_lid`),
      KEY `placement_b` (`date`,`blockStartTime`,`block_id`,`plannedPosition`),
      KEY `placement_material_id_mediaplan_id_index` (`material_id`,`mediaplan_id`),
      KEY `placement_material_id` (`material_id`,`mediaplan_id`,`order_id`),
      KEY `placement_material_id_mediaplan_id_order_id_block_id_index` (`material_id`,`mediaplan_id`,`order_id`,`block_id`),
      KEY `block_id_date_ind` (`block_id`,`date`),
      CONSTRAINT `FK6ADE12E521DC3251` FOREIGN KEY (`block_id`) REFERENCES `block` (`id`),
      CONSTRAINT `FK6ADE12E59B1CA2F1` FOREIGN KEY (`mediaplan_id`) REFERENCES `mediaplan` (`id`),
      CONSTRAINT `FK6ADE12E5AFA9B543` FOREIGN KEY (`material_id`) REFERENCES `material` (`id`),
      CONSTRAINT `FK_placement_1` FOREIGN KEY (`conflict_status_lid`) REFERENCES `lookups` (`id`),
      CONSTRAINT `FK_placement_2` FOREIGN KEY (`order_id`) REFERENCES `orders` (`id`),
      CONSTRAINT `FK_placement_3` FOREIGN KEY (`order_status_lid`) REFERENCES `lookups` (`id`),
      CONSTRAINT `FK_placement_4` FOREIGN KEY (`play_type_lid`) REFERENCES `lookups` (`id`),
      CONSTRAINT `FK_played_material` FOREIGN KEY (`played_material_id`) REFERENCES `played_material` (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=12578822 DEFAULT CHARSET=utf8 COMMENT='Розміщення рекламного матеріалу')
            ) ENGINE=InnoDB AUTO_INCREMENT=251369 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci        

exist 重写查询后我有下一个解释

    +----+--------------------+-------+------------+--------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------+---------+---------------------------+--------+----------+-------------+
    | id | select_type        | table | partitions | type   | possible_keys                                                                                                                                                     | key                   | key_len | ref                       | rows   | filtered | Extra       |
    +----+--------------------+-------+------------+--------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------+---------+---------------------------+--------+----------+-------------+
    |  1 | PRIMARY            | om    | NULL       | ALL    | NULL                                                                                                                                                              | NULL                  | NULL    | NULL                      | 243300 |    50.00 | Using where |
    |  6 | DEPENDENT SUBQUERY | o     | NULL       | eq_ref | PRIMARY                                                                                                                                                           | PRIMARY               | 4       | openmarket.om.order_id    |      1 |    50.00 | Using where |
    |  2 | DEPENDENT SUBQUERY | m     | NULL       | eq_ref | PRIMARY                                                                                                                                                           | PRIMARY               | 4       | openmarket.om.material_id |      1 |   100.00 | Using where |
    |  3 | DEPENDENT SUBQUERY | p     | NULL       | ref    | FK6ADE12E5AFA9B543,date_ind,placement_b,placement_material_id_mediaplan_id_index,placement_material_id,placement_material_id_mediaplan_id_order_id_block_id_index | placement_material_id | 5       | openmarket.m.id           |    101 |     0.82 | Using where |
    |  5 | DEPENDENT SUBQUERY | pr    | NULL       | ref    | FKED8DCCEF9B1CA2F1                                                                                                                                                | FKED8DCCEF9B1CA2F1    | 5       | openmarket.p.mediaplan_id |      1 |   100.00 | Using index |
    |  4 | DEPENDENT SUBQUERY | b     | NULL       | eq_ref | PRIMARY,FK597C48D47B04A3                                                                                                                                          | PRIMARY               | 4       | openmarket.p.block_id     |      1 |     5.00 | Using where |
    +----+--------------------+-------+------------+--------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------+---------+---------------------------+--------+----------+-------------+

最佳答案

据我从您的架构中了解到,您正在寻找一个不同的“order_materials”列表,以根据其他列出的表格进行过滤。 根据我的经验,您无法通过连接过滤/分组/区分结果而不会遭受“使用临时 - 使用文件排序”

无论如何,在你的情况下,因为看起来你不需要其他表中的值,我相信可以重写你的查询删除所有连接并只使用 EXISTS条款。

我会尝试这样的事情:

SELECT SQL_NO_CACHE om.*
FROM order_materials om 
where 
om.deleted = false
and 
exists (
    select 1 
    from material m
    where exists 
        (select 1 from placement p 
        where m.id = p.material_id 
        AND m.deleted = FALSE 
        AND p.deleted = FALSE
        and p.date >= '2018-03-01 00:00:00' AND p.date <= '2018-04-01 00:00:00'
        and exists (select 1 from block b
            where p.block_id = b.id 
            AND b.deleted = FALSE
            and b.advTable_id = 139
            )
        and exists (select 1 from product pr 
            where pr.mediaPlan_id = p.mediaplan_id)
        )
    and m.id=om.material_id
)
and exists (select 1 from orders o 
    where om.order_id = o.id 
    AND o.deleted = FALSE)

这样一个查询的解释计划是:

+------+--------------------+-------------+--------+-----------------------------------+--------------+---------+--------------------+------+-------------+
| id   | select_type        | table       | type   | possible_keys                     | key          | key_len | ref                | rows | Extra       |
+------+--------------------+-------------+--------+-----------------------------------+--------------+---------+--------------------+------+-------------+
|    1 | PRIMARY            | om          | ALL    | order_id,material_id              | NULL         | NULL    | NULL               |    1 | Using where |
|    1 | PRIMARY            | m           | eq_ref | PRIMARY                           | PRIMARY      | 4       | abc.om.material_id |    1 | Using where |
|    1 | PRIMARY            | o           | eq_ref | PRIMARY                           | PRIMARY      | 4       | abc.om.order_id    |    1 | Using where |
|    3 | DEPENDENT SUBQUERY | p           | ALL    | material_id,block_id,mediaplan_id | NULL         | NULL    | NULL               |    1 | Using where |
|    3 | DEPENDENT SUBQUERY | <subquery5> | eq_ref | distinct_key                      | distinct_key | 4       | func               |    1 |             |
|    3 | DEPENDENT SUBQUERY | b           | eq_ref | PRIMARY,advTable_id               | PRIMARY      | 4       | abc.p.block_id     |    1 | Using where |
|    5 | MATERIALIZED       | pr          | index  | mediaPlan_id                      | mediaPlan_id | 5       | NULL               |    1 | Using index |
+------+--------------------+-------------+--------+-----------------------------------+--------------+---------+--------------------+------+-------------+

如您所见,没有临时文件,也没有文件排序。因此,由于 exists 是一个 bool 运算符,您不会像加入时那样收到重复项。

最后,请格外小心:我是临时写下这个答案的,您需要检查嵌套的存在是否与您的预期结果一致,这不是最终解决方案,只是对我所做内容的共享提示到目前为止学到了。

关于mysql - 当解释看起来不错时如何改善查询时间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49251671/

相关文章:

mysql - 从不同的列中选择数据

mysql - SQL:根据文件编号添加特定日期的数量

sql - 如何根据旧记录插入新记录并使它们不同?

Neo4J - 将元素存储为用户属性或节点和关系哪个更好?

javascript - 表格不会在 AJAX 调用中消失

Java:从 MySQL DB 获取数据

PHP PDO SELECT LIMIT 问题

sql - 显示来自不同表的数据,并以摘要形式显示详细信息

sql - 是否有必要考虑删除现有索引,因为它是推荐索引的前缀

sql - N-M 关系中的复合主键与否?