我正在尝试提高此查询的性能:
SELECT Ts.[TripID]
,Ts.[RDate]
,Ts.[RTime]
,Ts.[Passengers]
,Ts.[Other]
,Ts.[RecordStatusID]
,IIF(Ts.RecordStatusID = 1, '', CONVERT(VARCHAR(10),
(SELECT SUM((IIF(Passengers + Other < 8, 1, CEILING((Passengers + Other) / 7.0))))
FROM dbo.tblTrips T
WHERE ISNULL(T.ActualDateTime, CAST(T.RDate AS SMALLDATETIME) + CAST(T.RTime AS SMALLDATETIME)) BETWEEN ISNULL(Ts.ActualDateTime, CAST(Ts.RDate AS SMALLDATETIME) + CAST(Ts.RTime AS SMALLDATETIME)) AND DATEADD(MINUTE, 35,
ISNULL(Ts.ActualDateTime, CAST(Ts.RDate AS SMALLDATETIME) + CAST(Ts.RTime AS SMALLDATETIME))) AND T.RecordStatusID > 1)) + ' Trips') AS Trips
FROM tblTrips Ts
ORDER BY Ts.RDate, Ts.RTime
我真的不确定如何以其他方式执行此操作,我们将不胜感激。
这里的目标是计算每行35分钟的间隔,显示从当前行程时间(rdate + rtime)+ 35分钟开始的行程,我尝试进行分组,但结果不是我想要的。我想知道是否有时间间隔的线索可以指定条件并对此进行计数?
答案 0 :(得分:1)
在提琴手上这是9毫秒,而您的解决方案是11毫秒 这个想法是将时间和日期字段合并一次,然后使用它。 对于其他部分,我并不确定您正在做什么。
;with cte as (
select *,ISNULL(ActualDateTime, CAST(RDate AS SMALLDATETIME) + CAST(RTime AS SMALLDATETIME)) TripsTime
,isnull(nullif(CEILING((Passengers + Other)/7.0),0),1) ICPO FROM tblTrips
)
select [TripID],[RDate],[RTime],[Passengers],[Other],[RecordStatusID]
, IIF(Ts.RecordStatusID = 1, '',
(select CONVERT(VARCHAR(10),SUM(ICPO))+ ' Trips' from cte T where
T.TripsTime between Ts.TripsTime and DATEADD(MINUTE, 35,Ts.TripsTime)
AND T.RecordStatusID > 1))
AS Trips
from cte Ts ORDER BY Ts.RDate, Ts.RTime
答案 1 :(得分:1)
我想您可以通过自我加入表格来避免相关子查询:
SELECT
Ts.[TripID]
,Ts.[RDate]
,Ts.[RTime]
,Ts.[Passengers]
,Ts.[Other]
,Ts.[RecordStatusID]
, IIF(Ts.RecordStatusID = 1, '',
cast(
SUM(IIF(tl.Passengers + tl.Other < 8, 1, CEILING((tl.Passengers + tl.Other) / 7.0)))
as varchar(10)
) + ' Trips') AS Trips
FROM
tblTrips Ts
inner join tblTrips Tl
on
Tl.RecordStatusID > 1
and (
(ts.tripid=tl.tripid and Ts.RecordStatusID = 1) or
( Ts.RecordStatusID > 1 and
ISNULL(Tl.ActualDateTime, CAST(Tl.RDate AS SMALLDATETIME) + CAST(Tl.RTime AS SMALLDATETIME)) BETWEEN
ISNULL(Ts.ActualDateTime, CAST(Ts.RDate AS SMALLDATETIME) + CAST(Ts.RTime AS SMALLDATETIME))
AND DATEADD(MINUTE, 35, ISNULL(Ts.ActualDateTime, CAST(Ts.RDate AS SMALLDATETIME) + CAST(Ts.RTime AS SMALLDATETIME)))
))
GROUP BY
Ts.[TripID]
,Ts.[RDate]
,Ts.[RTime]
,Ts.[Passengers]
,Ts.[Other]
,Ts.[RecordStatusID]
ORDER BY
Ts.RDate
, Ts.RTime
答案 2 :(得分:1)
您可以尝试拆分操作。例如:
DROP TABLE IF EXISTS #tblTrips;
DROP TABLE IF EXISTS #tblTripsAgg;
CREATE TABLE #tblTrips
(
[TripID] [int] NOT NULL
,[Record] INT
,[ActualDateTime] [datetime]
,PRIMARY KEY ([TripID])
);
CREATE TABLE #tblTripsAgg
(
[TripID] [int] NOT NULL PRIMARY KEY
,Trips INT
);
INSERT INTO #tblTrips ([TripID], [Record], [ActualDateTime])
SELECT TripID
,IIF(RecordStatusID = 1, 0, IIF(Passengers + Other < 8, 1, CEILING((Passengers + Other) / 7.0)))
,CAST(RDate AS SMALLDATETIME) + CAST(RTime AS SMALLDATETIME)
FROM tblTrips
INSERT INTO #tblTripsAgg
SELECT TS.[TripID]
,SUM(T.[Record])
FROM #tblTrips TS
LEFT JOIN #tblTrips T
ON T.[ActualDateTime] >= TS.[ActualDateTime]
AND T.[ActualDateTime] <= DATEADD(MINUTE, 35, TS.[ActualDateTime])
GROUP BY TS.[TripID]
SELECT A.[TripID]
,A.[RDate]
,A.[RTime]
,A.[Passengers]
,A.[Other]
,A.[RecordStatusID]
,IIF(A.RecordStatusID = 1, '', CONCAT(Trips, ' Trips')) AS Trips
FROM tblTrips A
INNER JOIN #tblTripsAgg DS
ON A.TripID = ds.TripID;
为什么?首先,因为有时复杂的查询无法通过SQL引擎正确优化,其次-您可以轻松地看到过程中哪一部分最慢。
例如,在上面的示例中,第一部分只是将我们的日期和时间放在一个日期中。另外,我们正在那里计算其他一些内容。因此,如果查询的这一部分花费大量时间,则只需使用触发器,使用计算的预计算列或应用程序触摸表时对其进行预计算即可。
然后在第二个查询中,我们计算每个trip id
的总和。如果这部分很慢,也许我们可以在包含ActualDateTime
的表上创建一个不同的索引,或者如果当前旅程ID的日期总是大于前一个,那么我们可以添加TS.TripID > T.TripID
来限制再行吗?
正如您在评论中所说,处理了30万行,但这确实是少量数据,因此执行它实际上不需要花费太多时间。如果您可以进一步优化查询,请共享数据转储。
您可以创建一个索引视图,以自动预先计算第一个查询的结果,因此不需要其他工作。
DROP VIEW IF EXISTS dbo.vw_tblTrips;
GO
CREATE VIEW dbo.vw_tblTrips WITH SCHEMABINDING
AS
SELECT TripID AS [TripID]
,IIF(RecordStatusID = 1, 0, IIF(Passengers + Other < 8, 1, CEILING((Passengers + Other) / 7.0))) AS [Record]
,CAST(RDate AS SMALLDATETIME) + CAST(RTime AS SMALLDATETIME) AS [ActualDateTime]
FROM dbo.tblTrips;
GO
CREATE UNIQUE CLUSTERED INDEX INX_vw_tblTrips
ON dbo.vw_tblTrips ([ActualDateTime], [TripID]);
GO