sql性能问题:查找路由

bnlyeluc  于 2021-06-20  发布在  Mysql
关注(0)|答案(3)|浏览(374)

我正在努力解决sql查询的性能问题
我坐火车旅行了5个站,名字是“a-b-c-d-e”。一位乘客只订了一张“b-c-d”的车票。我需要找回我的乘客去的所有车站。
我存储的内容:

  1. JOURNEY
  2. +----+--------------------+-------------------+-------------------+-----------------+
  3. | id | departure_datetime | arrival_datetime | departure_station | arrival_station |
  4. +----+--------------------+-------------------+-------------------+-----------------+
  5. | 1 | 2018-01-01 06:00 | 2018-01-01 10:00 | A | E |
  6. +----+--------------------+-------------------+-------------------+-----------------+
  7. BOOKING
  8. +----+------------+-------------------+-----------------+
  9. | id | journey_id | departure_station | arrival_station |
  10. +----+------------+-------------------+-----------------+
  11. | 1 | 1 | B | D |
  12. +----+------------+-------------------+-----------------+
  13. LEG
  14. +----+------------+-------------------+-----------------+------------------+------------------+
  15. | id | journey_id | departure_station | arrival_station | departure_time | arrival_time |
  16. +----+------------+-------------------+-----------------+------------------+------------------+
  17. | 1 | 1 | A | B | 2018-01-01 06:00 | 2018-01-01 07:00 |
  18. | 2 | 1 | B | C | 2018-01-01 07:00 | 2018-01-01 08:00 |
  19. | 3 | 1 | C | D | 2018-01-01 08:00 | 2018-01-01 09:00 |
  20. | 4 | 1 | D | E | 2018-01-01 09:00 | 2018-01-01 10:00 |
  21. +----+------------+-------------------+-----------------+------------------+------------------+

我找到的唯一能找回电台的方法是:

  1. select b.id as booking, l.departure_station, l.arrival_station
  2. from JOURNEY j
  3. inner join BOOKING b on j.id = b.journey_id
  4. inner join LEG dl on (j.id = dl.journey_id and b.departure_station = dl.departure_station)
  5. inner join LEG al on (j.id = al.journey_id and b.arrival_station = al.arrival_station)
  6. inner join LEG l on (j.id = l.journey_id and l.departure_time >= dl.departure_time and l.arrival_time <= al.arrival_time)
  7. where b.id = 1

但我的腿表很大,做这3个连接上是非常缓慢的。有没有办法我只能加入一次腿表,以提高性能?
预期回报:

  1. +------------+-------------------+-----------------+
  2. | booking_id | departure_station | arrival_station |
  3. +------------+-------------------+-----------------+
  4. | 1 | B | C |
  5. | 1 | C | D |
  6. +------------+-------------------+-----------------+

我在mariadb 12.2上工作,所以我可以访问窗口功能,但我仍然不太适应它。
谢谢。
编辑:创建表:

  1. CREATE TABLE `BOOKING` (
  2. `id` INT(11) NOT NULL,
  3. `journey_id` INT(11) NULL DEFAULT NULL,
  4. `departure_station` VARCHAR(50) NULL DEFAULT NULL,
  5. `arrival_station` VARCHAR(50) NULL DEFAULT NULL,
  6. PRIMARY KEY (`id`)
  7. );
  8. CREATE TABLE `JOURNEY` (
  9. `id` INT(11) NOT NULL AUTO_INCREMENT,
  10. `departure_time` DATETIME NULL DEFAULT NULL,
  11. `arrival_time` DATETIME NULL DEFAULT NULL,
  12. `departure_station` VARCHAR(50) NULL DEFAULT NULL,
  13. `arrival_station` VARCHAR(50) NULL DEFAULT NULL,
  14. PRIMARY KEY (`id`)
  15. );
  16. CREATE TABLE `LEG` (
  17. `id` INT(11) NOT NULL,
  18. `journey_id` INT(11) NULL DEFAULT NULL,
  19. `departure_station` VARCHAR(50) NULL DEFAULT NULL,
  20. `arrival_station` VARCHAR(50) NULL DEFAULT NULL,
  21. `departure_time` DATETIME NULL DEFAULT NULL,
  22. `arrival_time` DATETIME NULL DEFAULT NULL,
  23. PRIMARY KEY (`id`)
  24. );
kdfy810k

kdfy810k1#

我建议使用公共表表达式(cte):

  1. WITH leg_cte as
  2. (
  3. SELECT l.* FROM leg l
  4. JOIN booking b
  5. ON l.journey_id = b.journey_id
  6. WHERE b.id = 1
  7. )
  8. SELECT
  9. b.id as booking,
  10. l.departure_station,
  11. l.arrival_station
  12. FROM
  13. booking b
  14. JOIN leg_cte dl
  15. ON b.departure_station = dl.departure_station
  16. JOIN leg_cte al
  17. ON b.arrival_station = al.arrival_station
  18. JOIN leg_cte l
  19. ON l.departure_time >= dl.departure_time AND l.arrival_time <= al.arrival_time
  20. WHERE b.id = 1
展开查看全部
jchrr9hc

jchrr9hc2#

试试看 left join 使用 REGEXP 办理始发站到发站手续

  1. select T3.id booking_id , T1.departure_station,T1.arrival_station
  2. from LEG T1
  3. left join JOURNEY T2 on T1.`journey_id` = T2.`id`
  4. and (T1.`departure_time` >= T2.`departure_datetime` and T1.`arrival_time` <= T2.`arrival_datetime`)
  5. left join BOOKING T3 on T3.`id` = T2.`id`
  6. and T1.departure_station REGEXP (CONCAT('[',T3.departure_station , '-' , T3.arrival_station,']' ))
  7. and T1.arrival_station REGEXP (CONCAT('[',T3.departure_station , '-' , T3.arrival_station,']' ))
  8. where T1.journey_id = 1 and T3.id is not null ;

sql fiddle演示链接

  1. | booking_id | departure_station | arrival_station |
  2. |------------|-------------------|-----------------|
  3. | 1 | B | C |
  4. | 1 | C | D |

测试ddl:

  1. CREATE TABLE JOURNEY
  2. (`id` int, `departure_datetime` datetime, `arrival_datetime` datetime, `departure_station` varchar(1), `arrival_station` varchar(1))
  3. ;
  4. INSERT INTO JOURNEY
  5. (`id`, `departure_datetime`, `arrival_datetime`, `departure_station`, `arrival_station`)
  6. VALUES
  7. (1, '2018-01-01 06:00:00', '2018-01-01 10:00:00', 'A', 'E')
  8. ;
  9. CREATE TABLE BOOKING
  10. (`id` int, `journey_id` int, `departure_station` varchar(1), `arrival_station` varchar(1))
  11. ;
  12. INSERT INTO BOOKING
  13. (`id`, `journey_id`, `departure_station`, `arrival_station`)
  14. VALUES
  15. (1, 1, 'B', 'D')
  16. ;
  17. CREATE TABLE LEG
  18. (`id` int, `journey_id` int, `departure_station` varchar(1), `arrival_station` varchar(1), `departure_time` datetime, `arrival_time` datetime)
  19. ;
  20. INSERT INTO LEG
  21. (`id`, `journey_id`, `departure_station`, `arrival_station`, `departure_time`, `arrival_time`)
  22. VALUES
  23. (1, 1, 'A', 'B', '2018-01-01 06:00:00', '2018-01-01 07:00:00'),
  24. (2, 1, 'B', 'C', '2018-01-01 07:00:00', '2018-01-01 08:00:00'),
  25. (3, 1, 'C', 'D', '2018-01-01 08:00:00', '2018-01-01 09:00:00'),
  26. (4, 1, 'D', 'E', '2018-01-01 09:00:00', '2018-01-01 10:00:00')
  27. ;
展开查看全部
xzlaal3s

xzlaal3s3#

我不喜欢你的数据库模式。但在您的特殊情况下,因为您的查询对您有好处。我只需要创建几个索引,以加快执行速度。一般来说,当您需要将表本身连接几次时,并没有什么问题。
http://sqlfiddle.com/#!9/1a467/1号
尝试只添加4个索引:

  1. CREATE INDEX journey ON BOOKING (journey_id);
  2. CREATE INDEX arrival ON LEG (journey_id, arrival_station);
  3. CREATE INDEX departure ON LEG (journey_id, departure_station);
  4. CREATE INDEX d_a_time ON LEG (journey_id, departure_time, arrival_time);

再次运行查询,使用索引时应该会快得多。

相关问题