我正在修复大约一年前设计的相当复杂的 SSRS 报告中的缺陷。据我所知,编写报告的人——我们组织的一名承包商,现在已经离开,无法回答问题——几年前学习了 SQL,但没有跟上它的最新状态——他的代码充满了过时和不好的做法,例如加入 WHERE 子句,按列号而不是列名排序,以及始终使用临时表而不是子查询或 CTE。作为 SQL 的新手(不到一年的经验),我总是试图弄清楚我遇到的一些奇怪编码的目的,并了解它使用的任何过时技术的历史。这是我无法弄清楚的一个 - 我的报告的存储过程 m 目前在使用数据之前将所有内容都选择到临时表中。如果编码人员需要三列、50 行查找表中的两列,他会首先将这两列选择到临时表中。即使对于最终的 SELECT,他总是先选择一个临时表,然后执行 SELECT * 来访问数据。我以前没见过这个,对我来说似乎毫无意义。为什么不直接访问数据?在 SQL 的历史中,是否存在或曾经存在这样做的任何目的,或者只是简单的糟糕编码?以前没见过,对我来说似乎毫无意义。为什么不直接访问数据?在 SQL 的历史中,是否存在或曾经存在这样做的任何目的,或者只是简单的糟糕编码?以前没见过,对我来说似乎毫无意义。为什么不直接访问数据?在 SQL 的历史中,是否存在或曾经存在这样做的任何目的,或者只是简单的糟糕编码?
2 回答
我将对此进行猜测-使用临时表的原因。请注意,下面提到的推理只是一些观点,不一定是真正的原因。可能只是个人不知道编写 SQL 的正确方法。但是,这里有一些使用临时表的原因:
- 模拟视图——例如,他在 50 行表的 3 列中只选择 2 列,这意味着他实际上只想要这两列中数据的逻辑视图——这可以使用 CTE 轻松完成。
- 隔离数据更改 - 他想确保他始终在处理数据的副本,以便他与基表的数据更改隔离(本质上,这成为主表的快照)并且也不想使他的查询对基表执行意外修改。
- 性能 - 可能是他要查询的原始表的搜索和排序索引构建不佳 - 他碰巧通过构建临时表来弥补这一点,该索引构建在查询中所需的列上,这将帮助他实现更快的查询处理。它还将为他提供一种方法来防止对主表结构进行任何更改(这会减慢其他操作,例如插入和删除)。
话虽如此,重要的是要注意这些都是不好的编码实践。始终建议使用 SQL Server 提供的 CTE、Views 等工具来处理数据库中的数据。当您想在插入表之前对数据进行预处理并且在数据库之外这样做很昂贵(例如,想象一个从转储文件中读取数据并将它们插入到主表包含数百万行。可能是转储表包含重复数据,这些数据已经在表中持久化,因此我们不想插入这样的行。在这种情况下,数据处理系统可以转储候选行进入一个临时表,然后使用 SQL Server 强大的集合操作来过滤掉重复的行。)
根据您的描述,我称之为糟糕的编码。
在某些情况下,我可以想象按照您的描述进行选择。大多数属于“表需要很长时间才能读取”或“优化器无法有效使用表中的统计信息”的类别。一个原因可能是该表位于不同服务器上的数据库中。拥有本地副本通常会使查询更有效率。或者,“表”实际上可能是一个需要很长时间才能处理的视图。
另一种情况是当表格上有很多更新并且您出于某种原因想要一系列报告的快照时。您可能需要不同报告之间的一致性,因此将数据放入临时表可以保证这一点。
但是,一般来说,您永远不会这样做。如果您有一个小型参考表,您只需将其包含在from
子句中并访问您需要的列。SQL Server 在优化对表的访问和将处理仅限于需要的列方面做得很好。将东西放在临时表中会阻碍优化器——这通常(但不总是)是一件坏事。