如何优化包含来自同一个表的子查询的查询?

时间:2014-04-24 05:38:14

标签: sql sql-server sql-server-2008

我对ms sql很新,所以请原谅

我有一个表格,其中包含来自客户端和管理员的所有评论。我必须随着查询的放置时间和首次确认的时间选择唯一的会话。

查询是:

  SELECT CONVERT(DATE, [t0].[CommDate]) AS [CommDate2], [t0].[TicketId], [t0].[TransactionID], (
SELECT MIN([t1].[CommDate])
FROM [dbo].[CommentsHistory] AS [t1]
WHERE ([t1].[TicketId] = [t0].[TicketId]) AND ([t1].[CommentFrom] LIKE '%Client%')
) AS [AskedMinDate], (
SELECT MIN([t2].[CommDate])
FROM [dbo].[CommentsHistory] AS [t2]
WHERE ([t2].[TicketId] = [t0].[TicketId]) AND (NOT ([t2].[CommentFrom] LIKE '%Client%'))
) AS [ResponseMinDate] FROM [dbo].[CommentsHistory] AS [t0]
 WHERE (CONVERT(DATE, [t0].[CommDate]) >= DATEADD(mm,-1,GETDATE())) AND ([t0].[TicketId] IS NOT NULL)
ORDER BY [t0].[TicketId] DESC, [t0].[CommDate]

我已经应用了索引,但由于列内容不是唯一的,所以没有多大帮助。

还有其他方法可以编写这些类型的查询,还是应该考虑重构表本身?

上面的查询给出了结果,但速度太慢,我想知道我的查询不是优化的,或者我选择的表创建是错误的?

enter image description here

表格结构:

CREATE TABLE [dbo].[CommentsHistory](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [CommDate] [datetime] NULL CONSTRAINT [DF_CommentsHistory_CommDate]  DEFAULT (getdate()),
    [CommentFrom] [varchar](255) NULL,
    [Comments] [varchar](max) NULL,
    [TransactionID] [float] NULL,
    [splitnumber] [varchar](50) NULL,
    [MfrId] [int] NULL,
    [ShowClient] [bit] NULL,
    [ShowWareHouse] [bit] NULL,
    [IsResponse] [bit] NULL,
    [CustEmail] [varchar](150) NULL,
    [TicketId] [numeric](18, 0) NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

2 个答案:

答案 0 :(得分:1)

你没有提供任何数据来测试,但我的直觉是将子查询作为WITH子句运行会运行得更快,因为它们会运行一次并加入,而不是每次运行主结果集中的行。

  WITH CLIENTCOMMENTDATE
    AS (SELECT [t1].[TicketId], MIN([t1].[CommDate]) AS [CommDate]
          FROM [dbo].[CommentsHistory] AS [t1]
         WHERE ([t1].[CommentFrom] LIKE '%Client%')
         GROUP BY [t1].[TicketId]
       )
     , RESPONSEDATE
    AS (SELECT [t2].[TicketId], MIN([t2].[CommDate]) AS [CommDate]
          FROM [dbo].[CommentsHistory] AS [t2]
         WHERE (NOT ([t2].[CommentFrom] LIKE '%Client%'))
         GROUP BY [t2].[TicketId]
       )
SELECT CONVERT(DATE, [t0].[CommDate]) AS [CommDate2], 
       [t0].[TicketId], [t0].[TransactionID], 
       [t1].[CommDate] AS [AskedMinDate],
       [t2].[CommDate] AS [ResponseMinDate]
  FROM [dbo].[CommentsHistory] AS [t0]
  LEFT JOIN CLIENTCOMMENTDATE [t1] ON [t1].[TicketId] = [t0].[TicketId]
  LEFT JOIN RESPONSEDATE [t2] ON [t2].[TicketId] = [t0].[TicketId]
 WHERE (CONVERT(DATE, [t0].[CommDate]) >= DATEADD(mm,-1,GETDATE())) 
   AND ([t0].[TicketId] IS NOT NULL)
 ORDER BY [t0].[TicketId] DESC, [t0].[CommDate]
;

另一件能加速它的事情是,如果不是LIKE运算符,你可以使用等于运算符,例如 [CommentFrom] = 'Client'。这取决于评论来自客户端时CommentFrom列的内容是否始终正好'Client'。如果是,则可以使用相等运算符。如果没有,也许该列始终'Client'开始,或者它始终位于值中的相同位置,因此您可以使用LEFTSUBSTRING例如 LEFT([CommentFrom], 6) = 'Client'

答案 1 :(得分:0)

尝试使用OUTER APPLY,如下所示。

您可能需要在此查询中进行一些修改

SELECT CONVERT(DATE, [t0].[CommDate]) AS [CommDate2], 
        [t0].[TicketId], [t0].[TransactionID],
        A.AskedMinDate,
        B.ResponseMinDate 
FROM [dbo].[CommentsHistory] AS [t0]
OUTER APPLY (
            SELECT MIN([t1].[CommDate]) AS AskedMinDate
            FROM [dbo].[CommentsHistory] AS [t1]
            WHERE ([t1].[TicketId] = [t0].[TicketId]) AND ([t1].[CommentFrom] LIKE '%Client%')
) AS A
OUTER APPLY (
            SELECT MIN([t2].[CommDate]) AS ResponseMinDate
            FROM [dbo].[CommentsHistory] AS [t2]
            WHERE ([t2].[TicketId] = [t0].[TicketId]) AND (NOT ([t2].[CommentFrom] LIKE '%Client%'))
) AS B
WHERE (CONVERT(DATE, [t0].[CommDate]) >= DATEADD(mm,-1,GETDATE())) AND ([t0].[TicketId] IS NOT NULL)
ORDER BY [t0].[TicketId] DESC, [t0].[CommDate]