我有以下查询:
SELECT *
from stop_times
WHERE (departure_time BETWEEN '02:41' AND '05:41'
OR departure_time BETWEEN '26:41' AND '29:41')
AND stop_times.stop_id IN(51511,51509,51508,51510,6,53851,51522,51533)
在~800ms内返回134行。如果我分开它:
SELECT *
from stop_times
WHERE (departure_time BETWEEN '02:41' AND '05:41'
OR departure_time BETWEEN '26:41' AND '29:41')
在~10ms内返回~110k行并且
SELECT *
from stop_times
WHERE stop_times.stop_id IN(51511,51509,51508,51510,6,53851,51522,51533)
在~100ms内返回~5k行。
我尝试使用多列索引(departure_time和stop_id)以及2个单独的索引,但在任何一种情况下,第一个查询似乎都不会少于~800ms。我的stop_times表有大约3.5M行。有什么我可以丢失的,这会大大加快第一次查询的速度吗?
更新1:显示表创建:
CREATE TABLE `stop_times` (
`trip_id` varchar(20) DEFAULT NULL,
`departure_time` time DEFAULT NULL,
`stop_id` varchar(20) DEFAULT NULL,
KEY `index_stop_times_on_trip_id` (`trip_id`),
KEY `index_stop_times_on_departure_time_and_stop_id` (`departure_time`,`stop_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
不幸的是,stop_id和trip_id是varchars而不是整数是我无法控制的......
对于EXPLAIN
多列索引, 更新2: departure_time, stop_id
:
select_type: SIMPLE
type: range
rows: 239084
对于EXPLAIN
多列索引 stop_id, departure_time
:
select_type: SIMPLE
type: range
rows: 141
更新3: EXPLAIN
IN(51511,51509,51508,51510,6,53851,51522,51533)
select_type: SIMPLE
type: ALL
rows: 3556973 (lol)
EXPLAIN
的 IN("51511","51509","51508","51510","6","53851","51522","51533")
select_type: SIMPLE
type: range
rows: 141
答案 0 :(得分:3)
您是否创建了索引stop_id, departure_time
?因为departure_time, stop_id
绝对不会做任何事。
这是真的很难 - 它处理索引时可能有些坏事:(
你有一个范围,一个OR和一个非连续的IN - 它不会比那更糟。
尝试stop_id, departure_time
如果它没有用,那么除了切换到PostgreSQL之外没什么可做的。
您还可以尝试将查询重写为:
SELECT *
from stop_times
WHERE ( stop_times.stop_id IN(51511,51509,51508,51510,6,53851,51522,51533)
AND departure_time BETWEEN '02:41' AND '05:41'
)
OR ( stop_times.stop_id IN(51511,51509,51508,51510,6,53851,51522,51533)
AND departure_time BETWEEN '26:41' AND '29:41'
)
或:
SELECT *
from stop_times
WHERE ( stop_times.stop_id IN(51511,51509,51508,51510,6,53851,51522,51533)
AND departure_time BETWEEN '02:41' AND '05:41'
)
UNION ALL
SELECT *
from stop_times
WHERE ( stop_times.stop_id IN(51511,51509,51508,51510,6,53851,51522,51533)
AND departure_time BETWEEN '26:41' AND '29:41'
)
答案 1 :(得分:0)
您可以尝试一种可能性,即首先准备两个范围内发生的所有时间的列表,然后将它们粘贴在一个大的IN
子句中 - 它可能看起来很糟糕,但它将删除无法帮助您查询的OR
条件......您应该能够使用自己喜欢的编程语言构建IN
字符串:)
WHERE departure_time IN ('02:41','02:42','02:43', ... '26:41','26:42','26:43', ... etc )
您的查询包含两个三小时的块,相当于IN
子句中的6 * 60 = 360个条目......
值得一试至少......