我必须查询一个有几百万行的表,并且我想做到最优化。
假设我们要控制对具有多个放映室的电影院的访问,并将其保存如下:
AccessRecord
(TicketId,
TicketCreationTimestamp,
TheaterId,
ShowId,
MovieId,
SeatId,
CheckInTimestamp)
为简化起见,数据类型“bigint”和“时间戳”的“Id”列是“日期时间”。门票随时出售,人们随机进入剧院。主键(也是唯一的)是 TicketId。
我想为每个电影和剧院以及放映(时间)获取第一个和最后一个进入剧院看电影的人的 AccessRecord 信息。如果两个签到同时发生,我只需要 1 个,其中任何一个。
我的解决方案是在子查询中连接 PK 和分组列以获取行:
select
AccessRecord.*
from
AccessRecord
inner join(
select
MAX(CONVERT(nvarchar(25),CheckInTimestamp, 121) + CONVERT(varchar(25), TicketId)) as MaxKey,
MIN(CONVERT(nvarchar(25),CheckInTimestamp, 121) + CONVERT(varchar(25), TicketId)) as MinKey
from
AccessRecord
group by
MovieId,
TheaterId,
ShowId
) as MaxAccess
on CONVERT(nvarchar(25),CheckInTimestamp, 121) + CONVERT(varchar(25), TicketId) = MaxKey
or CONVERT(nvarchar(25),CheckInTimestamp, 121) + CONVERT(varchar(25), TicketId) = MinKey
转换 121 是数据时间的规范表达式,如下所示:aaaa-mm-dd hh:mi:ss.mmm(24h),因此作为字符串数据类型排序,它将给出与作为日期时间排序相同的结果。
如您所见,此连接不是很优化,有什么想法吗?
更新我如何测试不同的解决方案:
我已经在使用 SQL Server 2008 R2 的真实数据库中测试了您的所有答案,其中包含超过 3M 行的表以选择正确的。
如果我只得到第一个或最后一个访问的人:
- Joe Taras 的解决方案持续 10 秒。
- GarethD 的解决方案持续 21 秒。
如果我执行相同的访问但按分组列排序结果:
- Joe Taras 的解决方案持续 10 秒。
- GarethD 的解决方案持续 46 秒。
如果我得到两个(第一个和最后一个)访问有序结果的人:
- Joe Taras 的(做联合)解决方案持续 19 秒。
- GarethD 的解决方案持续 49 秒。
其余的解决方案(甚至是我的)在第一次测试中持续了 60 多秒,所以我取消了它。