【问题标题】:SQL query is slow. How can I make it faster?SQL 查询很慢。我怎样才能让它更快?
【发布时间】:2020-12-27 11:24:56
【问题描述】:

我有以下表格,它本质上是一个系统,可以告诉我谁在哪个房间:

CREATE TABLE customers
    (`cus_id` int PRIMARY KEY, `name` varchar(5), `driver_id` int)
;
    
INSERT INTO customers
    (`cus_id`, `name`, `driver_id`)
VALUES
    (1, 'bob', 11111),
    (2, 'james', 22222),
    (3, 'sam', 33333),
    (4, 'billy', 44444)
;


CREATE TABLE hotel_rooms
    (`hroom_id` int PRIMARY KEY, `name` varchar(10), `cus_id` int)
;
    
INSERT INTO hotel_rooms
    (`hroom_id`, `name`, `cus_id`)
VALUES
    (1, 'small room', 3),
    (2, 'big room', 1)
;


CREATE TABLE snapshots
    (`snapshot_id` int PRIMARY KEY, `hroom_id` int, FOREIGN KEY (hroom_id) REFERENCES hotel_rooms (hroom_id), `date_added` datetime)
;
    
INSERT INTO snapshots
    (`snapshot_id`, `hroom_id`, `date_added`)
VALUES
    (1, 1, '2020-01-12 12:43:13'),
    (2, 1, '2020-01-13 17:23:53'),
    (3, 2, '2020-01-19 07:34:01')
;


CREATE TABLE participants
    (`participant_id` int PRIMARY KEY, `snapshot_id` int, FOREIGN KEY (snapshot_id) REFERENCES snapshots (snapshot_id), `cus_id` int)
;
    
INSERT INTO participants
    (`participant_id`, `snapshot_id`, `cus_id`)
VALUES
    (1, 1, 1),
    (2, 1, 3),
    (3, 2, 1),
    (4, 2, 2),
    (5, 2, 3),
    (6, 3, 1),
    (7, 3, 4)
;

我的 SQL 语句:

SELECT s.snapshot_id, 
       hr.name, 
       c1.driver_id AS owner_driver_id,
       md.max_date AS date_added,
       GROUP_CONCAT(c2.driver_id) AS participants_driver_ids 
FROM snapshots s
JOIN (
  SELECT hr.hroom_id, MAX(date_added) AS max_date
  FROM hotel_rooms hr
  JOIN snapshots s ON s.hroom_id = hr.hroom_id
  JOIN participants p ON p.snapshot_id = s.snapshot_id
  JOIN customers c ON c.cus_id = p.cus_id
  WHERE c.cus_id = 1
  GROUP BY hr.hroom_id, hr.name
) md ON md.hroom_id = s.hroom_id AND md.max_date = s.date_added
JOIN hotel_rooms hr ON hr.hroom_id = s.hroom_id
JOIN customers c1 ON c1.cus_id = hr.cus_id
JOIN participants p ON p.snapshot_id = s.snapshot_id
JOIN customers c2 ON c2.cus_id = p.cus_id
GROUP BY s.snapshot_id, hr.name, c1.driver_id, md.max_date
;

表和语句的SQL代码:http://www.sqlfiddle.com/#!9/6844de/1

期望的输出:

基本上参与者表所说的是:

  • snapshot_id=1 bobsam 其中在 small room
  • snapshot_id=2bobjamessam 其中small room
  • snapshot_id=3bobbilly 其中在 big room

执行计划:

但是查询速度很慢。我不明白我需要索引什么才能使这个查询更快,因为它们基本上都是连接语句。

【问题讨论】:

  • 你看过执行计划了吗?它应该包含在您的帖子中。
  • 您是否添加了任何约束?尝试将主键约束添加到每个表的 ID 列,后跟外键引用
  • @Govind 抱歉,我更新了我的 sql 代码以添加主键和外键。我的实际实现有这些限制
  • @KenWhite 我怎么找到它
  • 了解您的查询速度很慢。但是,是否可以在此处提及您正在寻找的所需输出是什么,以便推荐一种可能更简单的替代方法而不是调试现有查询。

标签: mysql sql database indexing


【解决方案1】:

使用DATETIME,而不是VARCHAR 作为日期时间值。

请提供EXPLAIN SELECT...

用子查询进行实验——这将有助于确定缓慢是子查询还是其他原因。

snapshot 需要一个复合索引 INDEX(hroom, date_added),其中的列按该顺序排列。

【讨论】:

  • 和执行计划的key完全一样
  • 所以我添加了很多索引,什么没有。现在查询速度很快。但是,子查询(又名派生表)的类型是ALLEXPLAIN SELECT 中。如何加快派生表的速度?也许子查询是最好的方法?有没有办法可以在没有子查询的情况下重写语句?
  • @James - 小提琴在每个表中的行数太少,以至于我担心EXPLAIN。例如,由于 25% 的行是 cus_id=1,优化器可能会执行表扫描而不是使用索引。
【解决方案2】:

查询选择在客户 #1 拥有同一酒店房间的最后一个快照的同一天制作的所有快照。

我可能会把子查询写成

SELECT hroom_id, MAX(date_added) AS max_date
FROM snapshots s
WHERE snapshot_id IN (SELECT snapshot_id FROM participants WHERE cus_id = 1)
GROUP BY hroom_id

这清楚了意图,我删除了本次评估不需要的两个表。

此子查询的索引:

create index idx1 on participants (cus_id, snapshot_id);
create index idx2 on snapshots (snapshot_id, hroom_id, date_added);

主查询的索引:

create index idx3 on snapshots (hroom_id, date_added, snapshot_id);
create index idx4 on hotel_rooms (hroom_id, name);
create index idx5 on customers (cus_id, driver_id);
create index idx6 on participants (snapshot_id, cus_id);

【讨论】:

  • 我用您推荐的索引尝试了您的子查询。总共花了 0.0336 秒(包含数百万行数据)。这部分查询很快SELECT snapshot_id FROM participants WHERE cus_id = 1。外部查询很慢
  • 它根本不使用create index idx2 on snapshots (snapshot_id, hroom_id, date_added);。相反,它使用主键snapshot_id
  • 这有点令人惊讶。当我们提供客户 ID 并从参与者那里获取相关的快照 ID 时,合乎逻辑的下一步是获取这些快照 ID 并查找房间和日期。 idx2 是一个覆盖索引,我发现它可能用于此目的。使用 idx3,主查询可以快速使用子查询结果来获取所有快照以及参与者的 ID。不应该太慢。当然,连接和聚合需要时间。也许你对这个查询应该运行多快的期望有点太高了:-)
猜你喜欢
  • 1970-01-01
  • 2021-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-23
  • 2015-07-04
  • 2021-10-23
相关资源
最近更新 更多