现在的ORM是否仍然与MS SQL上的SELECT*有关的性能/代码可维护性问题?

Ben*_*Ben 12 sql sql-server orm sqlperformance database-performance

摘要:由于性能和可维护性问题,我已经看到很多反对在MS SQL 使用SELECT*的建议.然而,这些帖子很多都很老 - 5到10年!它似乎是,许多这些职位的,其性能的担忧可能实际上已经相当小,甚至在自己的时间,并作为可维护性关注("哦,不,如果有人改变了列,并且被索引获取数据一个数组!你的SELECT*会让你遇到麻烦!"),现代编码实践和ORM(如Dapper)似乎 - 至少在我的经验中 - 消除了这些问题.

所以:SELECT*是否存在今天仍然存在的问题?


更大的背景:我已经开始在一个有很多旧MS代码(ASP脚本等)的地方工作,但我一直在帮助实现大量现代化,但是:我的大部分SQL经验实际上来自于MySQL和PHP框架和ORM - 这是我第一次使用MS SQL - 我知道两者之间存在细微差别.另外:我的同事比我年长一点,并且有一些担忧 - 对我来说 - 似乎"老了".("可空的字段很慢!避免它们!")但是又一次:在这个特定的领域,他们肯定比我有更多的经验.

出于这个原因,我还想问一下:现代ORM中的SELECT*是否安全无瑕,是否有安全和明智的做法,是否有最新的在线资源表明这样?

谢谢!:)

Vla*_*nov 14

我不会在这个答案中触及可维护性,只有性能部分.

在这种情况下,性能与ORM几乎没有关系.

服务器如何生成它正在运行的查询无关紧要,无论是手动编写还是由ORM生成.

选择不需要的列仍然是一个坏主意.

从性能的角度来看,查询是否如下所示并不重要:

SELECT * FROM Table
Run Code Online (Sandbox Code Playgroud)

或明确列出所有列,例如:

SELECT Col1, Col2, Col3 FROM Table
Run Code Online (Sandbox Code Playgroud)

如果您只是需要Col1,请确保您只选择Col1.无论是通过手工编写查询还是通过微调ORM来实现,都无关紧要.


为什么选择不必要的列是一个坏主意:

  • 从磁盘读取的额外字节数

  • 通过网络传输的额外字节数

  • 在客户端上解析的额外字节

  • 但是,最重要的原因是优化者可能无法产生一个好的计划.例如,如果存在包含所有请求列的覆盖索引,则服务器通常只读取此索引,但如果您请求更多列,则会执行额外查找或使用其他索引,或者只扫描整个表.最终影响可以从可忽略不计到秒与运行时间之间变化.数据库越大越复杂,您就越有可能看到明显的差异.

有一篇关于这个主题的详细文章:使用索引,Luke网站上的选择*是不好的.

既然我们已经建立了一个共同的理解,为什么选择一切都不利于性能,你可能会问为什么它被列为神话?这是因为很多人认为明星是坏事.此外,他们认为他们没有犯下这一罪行,因为他们的ORM无论如何都列出了所有列.实际上,犯罪是选择所有列而不考虑它 - 并且大多数ORM代表其用户容易犯下此罪行.


我会在这里添加您的评论的答案.

我不知道如何处理一个ORM,它没有给我一个选项选项.我个人会尽量不使用它.一般来说,ORM添加了一层泄漏严重的抽象.https://en.wikipedia.org/wiki/Leaky_abstraction

这意味着您仍然需要知道如何编写SQL代码以及DBMS如何运行此代码,还需要知道ORM如何工作并生成此代码.如果您选择不知道ORM背后会发生什么,那么当您的系统变得超出微不足道时,您将遇到无法解释的性能问题.

你说在你以前的工作中你使用ORM来处理大型系统没有问题.它对你有用.好.不过,我有一种感觉,你的数据库并不是很大(你有数十亿行吗?)并且系统的性质允许隐藏缓存后面的性能问题(这并不总是可行的).系统可能永远不会超出硬件容量.如果您的数据适合缓存,通常在任何情况下都会相当快.只有当你越过某个阈值时,它才开始变得重要.之后突然一切都变得缓慢,很难修复它.

业务/项目经理通常忽略可能永远不会发生的未来可能的问题.企业总是有更紧迫的紧迫问题需要处理.如果业务/系统在性能成为问题时变得足够长,它将要么已经积累了足够的资源来重构整个系统,要么它将继续使用效率降低,或者如果系统恰好对业务非常关键,那么就失败了给另一家公司一个超越它的机会.

回答你的问题"是否在性能受到严重关注的应用中使用ORM".当然你可以使用ORM.但是,您可能会发现它比不使用它更困难.考虑到ORM和性能,您必须手动检查ORM生成的SQL代码,并从性能的角度确保它是一个很好的代码.因此,您仍然需要了解您使用得非常好的SQL和特定DBMS,并且您需要非常了解ORM以确保它生成您想要的代码.为什么不直接编写您想要的代码?

您可能认为ORM与原始SQL的这种情况有点类似于高度优化的C++编译器,而不是手动编写汇编程序中的代码.嗯,事实并非如此.在大多数情况下,现代C++编译器确实会生成比汇编器中手动编写的代码更好的代码.但是,编译器非常了解处理器,优化任务的性质比数据库中的要简单得多.ORM不知道您的数据量,它对您的数据分布一无所知.

简单的经典示例top-n-per-group可以通过两种方式完成,最佳方法取决于只有开发人员知道的数据分布.如果性能很重要,即使您手动编写SQL代码,也必须了解DBMS的工作原理并解释此SQL代码,并以DBMS以最佳方式访问数据的方式布置代码.SQL本身是一种高级抽象,可能需要微调以获得最佳性能(例如,SQL Server中有许多查询提示).DBMS有一些统计数据,它的优化器试图使用它,但它通常是不够的.

现在,在此之上添加另一层ORM抽象.

说完这一切之后,"表现"是一个模糊的术语.所有这些问题在一定的阈值后变得重要.由于现代硬件非常好,这个门槛已被推到相当远的地方,以允许很多项目忽略所有这些问题.

例.对具有百万行的表的最佳查询在10毫秒内返回.非最佳查询在1秒内​​返回.慢100倍.最终用户会注意到吗?也许,但可能并不重要.将表增长到十亿行,或者一个用户拥有1000个并发用户.1秒vs 100秒.最终用户肯定会注意到,即使比率(慢100倍)是相同的.实际上,随着数据的增长,比率会增加,因为各种缓存的用处越来越少.

  • 同意.大多数应用程序开发人员真的不了解可伸缩性能,因为在应用程序层中你可以添加更多的框(除非你有一个非常大的操作.)我很欣赏OP希望更好地理解,因为它不需要那么大的商店陷入数据问题.我建议好奇地拿起一本声誉良好的性能调优书,以便为构建真正可扩展的系统提供更好的基础. (2认同)

swe*_*swe 6

从SQL-Server-Performance-Point-of-view,你永远不应该使用select *,因为这意味着sqlserver从磁盘或ram读取完整的行.即使您需要所有字段,我也建议您不要这样做select *,因为您不知道,谁将任何数据附加到您的应用程序不需要的表中.有关详细信息,请参阅@ sandip-patel的答案

从DBA角度来看:如果您准确地给出了这些列名,那么dbadmin可以更好地分析和优化他的数据库.

从ORM-Point-Of-View更改列名,我建议不要使用select *.你想知道,如果表格改变了.如果基础表发生变化,如果没有出现错误,您希望如何为运行应用程序提供保证并给出正确的结果?

个人意见:我真的不能在需要表现良好的应用程序中使用ORM ...


swe*_*swe 5

这个问题已经过了一段时间了,似乎没有人能够找到Ben正在寻找的东西......

我认为这是,因为答案是"它取决于".

那里只是不IS THE ONE答案.

例子

  • 正如我之前所指出的,如果数据库不是您的,并且可能经常更改,则无法保证性能,因为使用select*每行的数据量可能会爆炸
  • 如果你使用ITS OWN数据库编写一个应用程序,没有人改变你的数据库(希望如此),你需要你的列,所以选择*有什么不对
  • 如果你构建某种延迟加载,"主要属性"即时加载,而其他人稍后加载(同一实体),你不能选择*因为你得到所有
  • 如果您使用select*,其他开发人员每次都会考虑"他是否考虑选择*",因为他们会尝试优化.所以你应该添加足够的评论......
  • 如果您在中间层构建3层应用程序构建大型缓存,并且性能是缓存完成的主题,您可以使用select*
  • 扩展3Tier:如果你有许多并发用户和/或非常大的数据,你应该考虑每一个字节,因为你必须扩大你的中间层,每个字节都浪费掉(正如有人在之前的评论中指出的那样)
  • 如果您为3个用户和数千个记录构建一个小应用程序,预算可能没有时间来优化速度/ db-layout /某些东西
  • 跟你的dba说话......他会告诉你什么声明必须改变/优化/剥离/ ......

我可以继续 没有一个答案.这取决于很多因素.