T-SQL数据库和/或查询的优化建议

时间:2016-04-22 21:43:19

标签: sql-server tsql indexing query-optimization

我正在努力寻找减少执行此查询所需时间的方法。现在,根据服务器的不同,它需要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)

2 个答案:

答案 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亿行,请制作一些索引。