8kb*_*8kb 4 best-practices stored-procedures dynamic-sql
假设我有两个经常针对我的数据库运行的查询:
SELECT
UserID,
UserName,
UserGender
FROM Users
WHERE UserID = @User
SELECT
UserID,
UserName,
UserGender
FROM Users
WHERE UserName LIKE @Name + '%
Run Code Online (Sandbox Code Playgroud)
它们应该在两个单独的存储过程中,还是只是一个使用 sp_executesql 动态创建语句的存储过程?
如果它们在两个存储过程中,那么如果我想在 SELECT 语句中添加或删除列,我将需要修改这两个过程。如果我使用动态 SQL,那么大概我会牺牲少量的性能。
在这种情况下,使用动态 SQL 的可维护性和遵守 DRY 原则(不要重复自己)会优先于存储过程的性能增益吗?
严格的 DRY 并不真正适用于数据库
我已经看到 DRY 被用作创建“重用”视图的理由。然后我们有意见加入意见等和小便表现不佳。
通常,类似的查询会以不同的方式使用。一个可能有一个聚合,一个可能没有,过滤器会有所不同(如上)。相似性并不能证明动态 SQL 的合理性,也不能证明视图的合理性。
在您上面的特定情况下,我会考虑使用 IF 语句来捕捉差异,特别是如果代码是由同一搜索页面或表单发布的:您具有基于使用的相似性,而不仅仅是使用相同的列和表。
此外,您还需要考虑安全性。
动态 SQL 需要 EXECUTE AS(权限提升)或对基表的权限。使用普通存储过程不需要这样的权限。
您可能还有不同的客户端代码:我们每个客户端都有存储过程(架构控制权限)。您想将所有表的选择权限授予所有客户端吗?
我不确定动态 SQL 是这里唯一的答案,但有时如果您的搜索参数变得相对复杂,它可能是最好的解决方案。在您提出的简单情况下,为什么不接受一个或两个参数的简单查询......
WHERE UserID = COALESCE(@User, UserID)
AND UserName LIKE COALESCE(@Name+'%', UserName)
Run Code Online (Sandbox Code Playgroud)
但是,如果搜索条件变得复杂,您将不得不考虑动态 SQL,因为 SQL Server 会在尝试为各种查询版本优化计划并尝试创建满足所有不同搜索条件的魔术计划时获得更好的运气。
您可以创建单独的存储过程,通过他们各自的搜索方法识别用户,只返回主键值,然后根据条件调用任何过程,将结果转储到 #temp 表中,然后在与基表的连接中定义选择列表的其余部分。前期要做更多的工作,但避免了维护问题,并允许您针对每个搜索条件优化存储过程。