我正在考虑对我的代码中特别重要的部分进行优化。它的任务是将统计数据插入表中。其他程序对这些数据的影响相当大。否则我会考虑使用 SQL 批量插入等。
所以我的问题是...
是否可以尝试插入一些数据,知道它可能(不太经常)为重复行抛出 SqlException?
异常对性能的影响是否比插入前检查每一行更糟糕?
我正在考虑对我的代码中特别重要的部分进行优化。它的任务是将统计数据插入表中。其他程序对这些数据的影响相当大。否则我会考虑使用 SQL 批量插入等。
所以我的问题是...
是否可以尝试插入一些数据,知道它可能(不太经常)为重复行抛出 SqlException?
异常对性能的影响是否比插入前检查每一行更糟糕?
首先,我的建议是在正确性方面犯错,而不是在速度方面犯错。当您完成项目并且分析显示您在插入行之前检查是否存在大量时间,然后才对其进行优化。
其次,我认为如果所有 RDBMS 中都有重复项,则存在插入和跳过的语法,所以这首先应该不是问题。我尽量避免将异常作为正常应用程序流程的一部分,并将它们留给真正的例外情况。也就是说,不要指望数据库中的异常来解决代码中的逻辑问题。在您的端(代码)上保持尽可能多的一致性,并让 DB 异常仅指示真正的错误。
在纯粹的性能级别上,插入数据并处理错误会更快,尤其是在错误不常见的情况下。运行选择查询以检查重复项、处理该结果,如果成功则插入,这将比插入和处理偶发错误慢得多。如果它引发异常,那么会慢一些,因为在大多数语言中异常处理都很慢,但是处理异常将比任何语言的 SQL 查询快很多倍。
正如 Assaf 所说,通常还有一种方法可以显式处理重复项,这样您就可以完全避免该错误。这将进一步提高性能,并允许您明确表明您正在以特定方式处理重复项。
是否使用存储过程取决于您 - 它可以以在数据库中添加更多逻辑为代价来提高性能。这是你必须做出的决定。我对此有过不好的经历,但这取决于 RDBMS 和您使用的语言。
我看不到存储过程会加速单例插入,除非涉及其他处理。不过可能会带来其他好处 - 将所有逻辑保持在一个位置等。
如果有重复等,我个人会插入并捕获错误。
如果您执行 IF NOT EXISTS 检查,然后有条件地 INSERT,则事务需要持有一个锁的时间间隔,这可能会增加表上的阻塞。
对于繁忙的插入表,值得检查表的碎片程度。如果您在 Identity / Auto-number 列上使用聚集 PK 插入,则所有插入都在一端(并且索引可以具有 100% 的填充因子),但如果插入在整个聚集索引中是随机的,那么您可能会出现页面拆分等问题。
一个相关的问题是表上的统计信息可能很快就会过时,这可能会影响使用缓存查询计划等的查询的性能。
我认为最好使用存储过程,并使用 IF
IF (SELECT COUNT(*) FROM X WHERE Y=Z)=0 INSERT INTO (X) VALUES('XX')....
你可以添加一个 ELSE 条件......
是的,我会一直检查。例如电子邮件地址或 IP 地址。
如果您担心性能,请使用存储过程来处理重复的逻辑。
可能与这里的问题不太相关。
但是我在一个项目中工作,在以编程方式删除表之前,它用于检查表是否存在。
当我们开始优化代码时,我们将其更改为处理特定的异常,而不是在删除之前检查表是否存在。
而且我们有一些相当大的时间改进,因为我们在流程中多次使用存在性检查。
有了这种思路,我认为处理异常而不是另一个数据库查询进行检查的成本更低。
在高负载并发环境中,检查东西是否存在是不够的,因为会有竞争条件并且行将被插入到其他存在检查之间。所以你要么必须做一个检查后锁定(它本身很容易出现竞争条件),要么再次处理异常以防其他数据能够潜入。