在用于数据子集的交互式分析的脚本中,将查询结果存储到临时表中以供进一步分析通常很有用。
我的许多分析脚本都包含这种结构:
CREATE TABLE #Results (
a INT NOT NULL,
b INT NOT NULL,
c INT NOT NULL
);
INSERT INTO #Results (a, b, c)
SELECT a, b, c
FROM ...
SELECT *
FROM #Results;
在 SQL Server 中,临时表是连接范围的,因此查询结果在初始查询执行后仍然存在。当我要分析的数据子集的计算成本很高时,我会使用此方法而不是使用表变量,因为该子集会在不同批次的查询中持续存在。
脚本的设置部分运行一次,随后的查询(SELECT * FROM #Results
这里是占位符)会根据需要经常运行。
偶尔,我想刷新临时表中的数据子集,所以我再次运行整个脚本。一种方法是通过将脚本复制到 Management Studio 中的新查询窗口来创建新连接,我发现这很难管理。
相反,我通常的解决方法是在 create 语句之前添加一个条件 drop 语句,如下所示:
IF OBJECT_ID(N'tempdb.dbo.#Results', 'U') IS NOT NULL
BEGIN
DROP TABLE #Results;
END;
该语句正确处理了两种情况:
- 在表不存在时的第一次运行:什么都不做。
- 在表确实存在的后续运行中:删除表。
我编写的生产脚本将始终使用这种方法,因为它在两种预期情况下都不会引发错误。
我的其他开发人员编写的一些等效脚本有时会使用异常处理来处理这两种情况:
BEGIN TRY DROP TABLE #Results END TRY BEGIN CATCH END CATCH
我相信在数据库世界里,请求许可总比寻求宽恕好,所以这种方法让我感到不安。
第二种方法在不采取任何措施处理非异常行为(表不存在)时吞下错误。此外,由于表不存在以外的其他原因,可能会引发错误。
聪明的猫头鹰警告同样的事情:
在这两种方法中,[
OBJECT_ID
method] 更难理解,但可能更好:使用 [BEGIN TRY
method],您冒着捕获错误错误的风险!
但它没有解释实际风险是什么。
实际上,该BEGIN TRY
方法从未在我维护的系统中引起问题,因此我很高兴它留在那里。
使用方法管理临时表存在有哪些可能的危险BEGIN TRY
?空的 catch 块可能会隐藏哪些意外错误?