用于将VARBINARY转换为VARCHAR和charindex的查询优化

时间:2014-10-13 21:22:06

标签: sql sql-server performance sql-server-2012 varbinary

我有一个存储库表,其中有大约1870万行,每个月都会添加大约50万到10万行。表结构如下

CREATE TABLE [dbo].[my_table](
    [id] [bigint] NULL,
    [a_timestamp] [datetime] NULL,
    [eventId] [bigint] NULL,
    [userId] [varchar](255) NULL,
    [customerid] [varchar](128) NULL,
    [messageType] [varchar](100) NULL,
    [message] [varbinary](max) NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

我写了以下查询以获取每个月的各种计数。查询大约需要10分钟才能执行。我需要帮助来优化此查询,如果可能的话,将时间花费几分钟。

SELECT DATEADD(month, DATEDIFF(month, 0,a_timestamp), 0) AS MonthYear, 
       COUNT(*) AS [Count], 
       COUNT(DISTINCT customerid) AS [Unique Customers], 
       COUNT(DISTINCT userId) AS  [Unique Users]
FROM [my_table]
WHERE messageType = 'Outbound'
AND userId NOT IN ('master', 'admin')
AND CHARINDEX('Retrieve Document',CONVERT(VARCHAR(MAX),[message])) > 1
GROUP BY DATEADD(month, DATEDIFF(month, 0,a_timestamp), 0) 
ORDER BY MonthYear

我认为执行时间长的关键原因如下

  • CHARINDEX('Retrieve Document',CONVERT(VARCHAR(MAX),[message])) > 1从VARBINARY转换为VARCHAR并搜索是否'检索文档'
  • userId NOT IN ('master', 'admin')过滤列表中用户以外的用户(实际列表超过10个字符串的2个字符串)
  • 表中的1870万行

需要注意几点

  • 我没有创建此表,我无法更改
  • 我没有SHOWPLAN权限
  • 我需要在Excel数据连接中使用此查询,并让用户从excel运行它。用户将只有选择权限。

1 个答案:

答案 0 :(得分:1)

鉴于您无法更改现有表格,最好更改策略。 而不是每次都完全运行查询并构建一组新结果。为什么不按月将新结果插入另一个表(我们称之为AccumulatedResults)。

这样你每次只处理500K新的rec。这比每次重建整个结果集要快得多。查询看起来有点像:

INSERT INTO AccumulatedResults
(
  MonthYear,
  [COUNT],
  UniqueCustomers,
  UniqueUsers,
)  
SELECT
  DATEADD(month, DATEDIFF(month, 0, a_timestamp), 0) AS MonthYear,
  COUNT(*) AS [Count],
  COUNT(DISTINCT customerid) AS [Unique Customers],
  COUNT(DISTINCT userId) AS [Unique Users]
FROM
  [my_table]
WHERE
  messageType = 'Outbound' AND
  userId NOT IN ('master', 'admin') AND
  CHARINDEX('Retrieve Document', CONVERT(VARCHAR(MAX), [message])) > 1

  -- This is a new condition
  AND DATEADD(month, DATEDIFF(month, 0, a_timestamp), 0) 
  > (SELECT MAX(MonthYear) FROM AccumulatedResults)

GROUP BY
  DATEADD(month, DATEDIFF(month, 0, a_timestamp), 0)