我正在努力寻找减少执行此查询所需时间的方法。现在,根据服务器的不同,它需要30-90分钟。我还在学习索引,这是未来项目的一个选择,我也在寻找可能有助于优化查询本身的建议。数据库非常大,主表中包含1000到1亿行。任何的意见都将会有帮助!
(我已将列名更改为对此帖更具描述性)
USE MyDB
DECLARE @interval int = 6
DECLARE @mindate DATETIME = (SELECT DATEADD(HOUR, DATEDIFF(HOUR,0,MIN(DateColumn))/@interval*@interval, 0) FROM MyTable1)
DECLARE @maxdate DATETIME = (SELECT DATEADD(HOUR, DATEDIFF(HOUR,0,MAX(DateColumn))/@interval*@interval, 0) FROM MyTable1)
DECLARE @end DATETIME = (SELECT DATEADD(HOUR, DATEDIFF(HOUR,0,GETDATE())/@interval*@interval, 0))
--=========================================================
-- Update all DATEADD statements to desired interval
--=========================================================
;WITH cte
AS (SELECT
[StartTime] = CONVERT(datetime,@mindate),
[EndTime] = DATEADD(HOUR, @interval, CONVERT(datetime,@mindate))
UNION ALL
SELECT
DATEADD(HOUR, @interval, [StartTime]),
DATEADD(HOUR, @interval, [EndTime])
FROM cte
WHERE [EndTime] < @end)
--==========================================================
SELECT
[ServerName] = ServerName,
[StartTime] = CONVERT(varchar, [StartTime], 121),
[EndTime] = CONVERT(varchar, [EndTime], 121),
[ItemsMigrated] = COUNT(ItemIDColumn),
[SizeMigrated] = ISNULL(SUM(ItemSizeColumn),0),
[ItemsFailed] = (SELECT COUNT(*) FROM MyTable2 WHERE ItemStatusColumn = "Failed")
FROM cte
LEFT JOIN MyTable1 cr ON cr.DateColumn >= [StartTime] AND cr.DateColumn < [EndTime]
GROUP BY cte.StartTime, cte.EndTime
ORDER BY cte.StartTime
OPTION (MAXRECURSION 0)
答案 0 :(得分:1)
1。 正如其他人已经提到的,您可以执行以下语句并将其存储在变量中或将其作为子查询加入。你当前的方式(至少根据我的经验),它将在你返回的每一行执行行,这肯定会减慢你的查询速度。
(SELECT COUNT(*) FROM MyTable2 WHERE ItemStatusColumn = "Failed")
2。 如果@Mindate已经是日期时间,那么您不需要进行以下转换。
CONVERT(datetime,@mindate)
3。 正如其他人已经提到的,将CTE加载到临时表或表变量中。重要的是,设置哪些列为NULL / NOT NULL以及哪一列是主键(如果可能),因为这样可以加快速度。
4。 一点点细节,但@interval需要是int吗?我很确定你可以使用tinyint作为数据类型而不是int。
5。 根据您的表MyTable1,您可以使用&#34; with(nolock)&#34;根据您的情况,有时可以提高性能。但要非常小心,因为&#34;与(nolock)&#34;如果在尝试访问表时有大量插入/更新/删除,则可能会得到不完整的数据。如果这是您的临时表,您是唯一访问该表的人,那么使用&#34; with(nolock)&#34;可能是安全的。加速事情。
https://www.mssqltips.com/sqlservertip/2470/understanding-the-sql-server-nolock-hint/
答案 1 :(得分:1)
删除迭代整个数据集的select语句:
DECLARE @mindate DATETIME = (SELECT DATEADD(HOUR, DATEDIFF(HOUR,0,MIN(DateColumn))/@interval*@interval, 0) FROM MyTable1)
DECLARE @maxdate DATETIME = (SELECT DATEADD(HOUR, DATEDIFF(HOUR,0,MAX(DateColumn))/@interval*@interval, 0) FROM MyTable1)
可以
DECLARE @mindate DATETIME
DECLARE @maxdate DATETIME
SELECT @mindate = DATEADD(HOUR, DATEDIFF(HOUR,0,MIN(DateColumn))/@interval*@interval, 0),
@maxdate = DATEADD(HOUR, DATEDIFF(HOUR,0,MAX(DateColumn))/@interval*@interval, 0)
FROM MyTable1
此外,将日期时间转换为日期时间将无效,编译器将忽略该日期时间,但您将每个行的日期时间转换为varchar。这将加起来有1亿行。 而是做一次,因为这些日期时间不会改变。
SELECT
[StartTime] = CONVERT(datetime,@mindate),
[EndTime] = DATEADD(HOUR, @interval, CONVERT(datetime,@mindate))
[StartTimeS] = CONVERT(varchar, @mindate, 121),
[EndTimeS] = CONVERT(varchar, DATEADD(HOUR, @interval, CONVERT(datetime,@mindate)), 121),
[ItemsFailed] = (SELECT COUNT(*) FROM MyTable2 WHERE ItemStatusColumn = "Failed")
UNION ALL
SELECT
DATEADD(HOUR, @interval, [StartTime]),
DATEADD(HOUR, @interval, [EndTime])
CONVERT(varchar, DATEADD(HOUR, @interval, [StartTime]), 121),
CONVERT(varchar, DATEADD(HOUR, @interval, [EndTime]), 121),
[ItemsFailed]
FROM cte
然后你有
SELECT
[ServerName] = ServerName,
[StartTime] = StartTimeS,
[EndTime] = EndTimeS,
[ItemsMigrated] = COUNT(ItemIDColumn),
[SizeMigrated] = ISNULL(SUM(ItemSizeColumn),0),
[ItemsFailed]
但请记住,100米行仍然是100米行,需要一些时间。如果你正在进行任何加入,你需要一个索引,不要有疯狂的性能影响。
(例如,连接到没有索引的10行表将导致数据库额外读取10亿次。)
如果你有1亿行,请制作一些索引。