Pie*_*arg 41 sql-server select sql-server-2012
在过去的日子里,这被认为是一个很大的禁忌select * from table或select count(*) from table因为性能受到影响。
在 SQL Server 的更高版本中是否仍然如此(我使用的是 2012,但我想这个问题适用于 2008 - 2014)?
编辑:由于人们似乎在这里稍微批评我,我是从基准/学术的角度来看这个的,而不是这是否是“正确”的事情(当然不是)
RLF*_*RLF 50
如果您SELECT COUNT(*) FROM TABLE只返回一行(计数),则相对较轻,并且是获取该数据的方法。
并且SELECT *不是身体上的禁忌,因为它是合法且被允许的。
但是,问题SELECT *在于您可能会导致更多的数据移动。您对表中的每一列进行操作。如果您SELECT只包含几列,您可能能够从一个或多个索引中获得答案,这会减少 I/O 以及对服务器缓存的影响。
因此,是的,建议不要将其作为一般做法,因为这会浪费您的资源。
唯一真正的好处SELECT *是不用输入所有的列名。但是从 SSMS 中,您可以使用拖放操作来获取查询中的列名并删除不需要的列名。
打个比方:如果有人SELECT *在不需要每一列时使用,当他们不需要每一行时,他们是否也会使用SELECTwithout a WHERE(或其他限制子句)?
Stu*_*ler 24
除了已经提供的答案之外,我觉得值得指出的是,开发人员在使用现代 ORM(例如实体框架)时通常太懒了。虽然 DBA 尽最大努力避免SELECT *,但开发人员经常编写语义上等效的,例如,在 c# Linq 中:
var someVariable = db.MyTable.Where(entity => entity.FirstName == "User").ToList();
Run Code Online (Sandbox Code Playgroud)
本质上,这将导致以下结果:
SELECT * FROM MyTable WHERE FirstName = 'User'
Run Code Online (Sandbox Code Playgroud)
还有一个尚未涵盖的额外开销。那就是将每一行的每一列处理成相关对象所需的资源。此外,对于保存在内存中的每个对象,都必须清除该对象。如果你只选择了你需要的列,你可以轻松地节省超过 100mb 的内存。虽然它本身不是大量的,但它是垃圾收集等的累积效应,这是成本客户端。
所以是的,至少对我来说,这是并且永远是一个很大的不。我们还需要教育更多这样做的“隐藏”成本。
附录
以下是根据评论中的要求仅提取所需数据的示例:
var someVariable = db.MyTable.Where(entity => entity.FirstName == "User")
.Select(entity => new { entity.FirstName, entity.LastNight });
Run Code Online (Sandbox Code Playgroud)
Gre*_*ker 13
性能:带有 SELECT * 的查询可能永远不会是覆盖查询(简单的谈话解释,堆栈溢出解释)。
面向未来:您的查询今天可能会返回所有 7 列,但如果有人在明年添加了 5 列,那么在一年内您的查询将返回 12 列,浪费 IO 和 CPU。
索引:如果您希望视图和表值函数参与 SQL Server 中的索引,那么必须使用架构绑定创建这些视图和函数,这禁止使用 SELECT *。
最佳实践:永远不要SELECT *在生产代码中使用。
对于子查询,我更喜欢WHERE EXISTS ( SELECT 1 FROM … ).
编辑:为了解决下面 Craig Young 的评论,在子查询中使用“SELECT 1”不是“优化”——这样我就可以站在我的班级面前说“不要使用 SELECT *,没有例外! ”
我能想到的唯一例外是客户端正在执行某种数据透视表操作并且确实需要所有当前和未来的列。
我可能会接受涉及 CTE 和派生表的异常,但我想查看执行计划。
请注意,我认为COUNT(*)这是一个例外,因为它是“*”的不同语法用法。
RBa*_*ung 10
在 SQL Server 2012(或 2005 年以后的任何版本)中, usingSELECT *...只是查询的顶级 SELECT 语句中可能存在的性能问题。
所以它不是在视图(*),子查询中不存在的条款,在热膨胀系数的问题,也不在SELECT COUNT(*)..等,等。注意,这可能也适用于Oracle和DB2,以及也许Postgres的(不知道) ,但是很可能在很多情况下对于MySql来说仍然是一个问题。
要理解为什么(以及为什么它仍然可能是顶级 SELECT 中的一个问题),理解为什么它曾经是一个问题是有帮助的,这是因为使用SELECT *..手段“返回所有列”。一般来说,这将返回大量的数据比你真正想要的,这显然会导致其它更多的IO,磁盘和网络。
不太明显的是,这也限制了 SQL 优化器可以使用的索引和查询计划,因为它知道它最终必须返回所有数据列。如果它可以提前知道您只需要某些列,那么它通常可以通过利用只有这些列的索引来使用更有效的查询计划。幸运的是,它有一种方法可以提前知道这一点,即您可以在列列表中明确指定所需的列。但是当你使用“*”时,你放弃了这一点,而倾向于“给我一切,我会弄清楚我需要什么”。
是的,还有额外的 CPU 和内存使用来处理每一列,但与这两件事相比,它几乎总是微不足道的:您不需要的列需要大量额外的磁盘和网络带宽,并且必须使用更少的优化的查询计划,因为它必须包含每一列。
那么发生了什么变化?基本上,SQL 优化器成功地合并了一个称为“列优化”的功能,这只是意味着,如果您要在查询的上层实际使用列,它们现在可以在较低层的子查询中确定。
这样做的结果是,如果您在查询的较低/内部级别使用 'SELECT *..' 不再重要。相反,真正重要的是顶级 SELECT 的列列表中的内容。除非您SELECT *..在顶部使用,否则它必须再次假设您需要所有列,因此不能有效地使用列优化。
(* -- 请注意,视图中存在一个不同的小绑定问题,*当使用“*”时,它们并不总是注册列列表中的更改。还有其他方法可以解决这个问题,并且不会影响性能。)
还有一个不使用的小原因SELECT *:如果返回的列的顺序发生变化,您的应用程序将会中断……如果您很幸运的话。如果不是,您将有一个可能在很长一段时间内未被发现的微妙错误。表中字段的顺序是一个实现细节,应用程序永远不应考虑它,因为它唯一可见的时间是如果您使用SELECT *.
| 归档时间: |
|
| 查看次数: |
11855 次 |
| 最近记录: |