使用同义词的SQL Server查询性能问题

时间:2017-07-25 13:56:57

标签: sql sql-server

我想根据我的数据库表检查同义词表记录。

以下声明对我来说很好,但我想摆脱插入和临时表:

IF OBJECT_ID('tempdb..#tmp_table') IS NOT NULL
     DROP TABLE #tmp_table

SELECT 
    id 
INTO
    #tmp_table
FROM
    synonyms_table WITH (nolock)  
WHERE
    created_date BETWEEN GETDATE() - 4 AND GETDATE() - 1 

SELECT id
FROM #tmp_table tmp    
LEFT JOIN main_table main WITH (NOLOCK) ON tmp.id COLLATE SQL_Latin1_General_CP1_CI_AS = main.id
WHERE main.id IS NULL

问题是,两个表都很大,如果我要使用左连接或不存在,它将会非常慢:

SELECT id 
FROM synonyms_table sy WITH (NOLOCK) 
LEFT JOIN main_table main WITH (NOLOCK) ON sy.id COLLATE SQL_Latin1_General_CP1_CI_AS = main.id
WHERE sy.created_date BETWEEN GETDATE() - 4 AND GETDATE() - 1 
  AND main.id IS NULL

也许有人在这里知道一个很好的解决方案:)

2 个答案:

答案 0 :(得分:1)

如果您的目标是从同义词表中获取主表中不存在的记录,则应使用NOT EXISTS。它应该表现得更好,但在你尝试之前你不会知道。

SELECT Id
FROM synonyms_table s
WHERE s.created_date BETWEEN DATEADD(DAY, -4, GETDATE()) 
    AND DATEADD(DAY, -1, GETDATE()))
AND NOT EXISTS 
(
   SELECT * FROM main_table m 
   WHERE m.Id = s.Id COLLATE DATABASE_DEFAULT
)

但是,如果#temp表解决方案工作得更好,我肯定会保留它。事实上,我会建议两项改进,可以进一步提高它的性能。

1)您可以通过将COLLATE添加到SELECT INTO

来代替在连接中使用COLLATE(价格昂贵),而是可以使用正确的排序规则创建临时表
SELECT id COLLATE SQL_Latin1_General_CP1_CI_AS AS Id  
INTO #tmp_table
FROM synonyms_table

2)在创建临时表之后和加入

之前,在临时表上创建聚簇索引
CREATE CLUSTERED INDEX ix_tmp_table ON #tmp_table (Id)

答案 1 :(得分:0)

你可以尝试这样的事情,记住优化者可能决定运行一个可以追溯到非性能版本的执行计划:

WITH Base AS (
    SELECT 
        id COLLATE DATABASE_DEFAULT AS id
    FROM 
        synonyms_table WITH (NOLOCK)
    WHERE
        created_date BETWEEN DATEADD(DAY, -4, GETDATE()) AND DATEADD(DAY, -1, GETDATE()))
SELECT
    id
FROM
    Base b
    LEFT JOIN main_table main WITH (NOLOCK) ON b.id = main.id
WHERE 
    main.id IS NULL;

您的一个开销是排序规则,因此我预先整理公用表表达式中的数据。