我想根据我的数据库表检查同义词表记录。
以下声明对我来说很好,但我想摆脱插入和临时表:
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
也许有人在这里知道一个很好的解决方案:)
答案 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;
您的一个开销是排序规则,因此我预先整理公用表表达式中的数据。