Stu*_*tLC 9 sql-server maintainability constants
我已经看到了几种用于"克服"SQL Server中缺少常量的模式,但它们似乎都没有满足性能和可读性/可维护性问题.
在下面的示例中,假设我们在表上有一个完整的"状态"分类,选项似乎是:
-- StatusId 87 = Loaded
SELECT ... FROM [Table] WHERE StatusId = 87;
Run Code Online (Sandbox Code Playgroud)
WHERE子句引用友好名称.子查询:
SELECT ...
FROM [Table]
WHERE
StatusId = (SELECT StatusId FROM TableStatus WHERE StatusName = 'Loaded');
Run Code Online (Sandbox Code Playgroud)
或加入
SELECT ...
FROM [Table] t INNER JOIN TableStatus ts On t.StatusId = ts.StatusId
WHERE ts.StatusName = 'Loaded';
Run Code Online (Sandbox Code Playgroud)
CREATE Function LoadedStatus()
RETURNS INT
AS
BEGIN
RETURN 87
END;
Run Code Online (Sandbox Code Playgroud)
然后
SELECT ... FROM [Table] WHERE StatusId = LoadedStatus();
Run Code Online (Sandbox Code Playgroud)
(IMO会导致数据库中出现大量污染 - 在Oracle软件包中可能没问题)
CROSS APPLIED返回的[Table]其他SO用户如何解决这个常见问题?
编辑:赏金 - 根据Remus的回答和评论,有没有人在DBProj DDL/Schema脚本中维护$(变量)的最佳实践方法?
Rem*_*anu 13
硬编码.SQL性能胜过可维护性.
使用优化程序在计划生成时可以检查的常量与使用任何形式的间接(UDF,JOIN,子查询)之间的执行计划的后果通常是戏剧性的.SQL'编译'是一个非同寻常的过程(在某种意义上说,不像IL代码生成那样'普通'),因为结果不仅由编译的语言结构(即查询的实际文本)决定,而且还由由数据模式(现有索引)和那些索引中的实际数据(统计数据).当使用硬编码值时,优化器可以提供更好的计划,因为它实际上可以根据索引统计信息检查值并获得结果的估计值.
另一个考虑因素是SQL应用程序不仅仅是代码,而是大量的代码和数据."重构"SQL程序是......不同的.在C#程序中,可以更改常量或枚举,重新编译并愉快地运行应用程序,在SQL中不能这样做,因为该值可能存在于数据库中的数百万条记录中,并且更改常量值意味着也会更改数据的GB ,经常在线进行新操作.
仅仅因为值在服务器看到的查询和过程中是硬编码的,并不一定意味着必须在原始项目源代码中对值进行硬编码.有各种代码生成工具可以解决这个问题.考虑一下像利用sqlcmd脚本变量一样简单:
defines.sql:
:setvar STATUS_LOADED 87
Run Code Online (Sandbox Code Playgroud)
somesource.sql:
:r defines.sql
SELECT ... FROM [Table] WHERE StatusId = $(STATUS_LOADED);
Run Code Online (Sandbox Code Playgroud)
someothersource.sql:
:r defines.sql
UPDATE [Table] SET StatusId = $(STATUS_LOADED) WHERE ...;
Run Code Online (Sandbox Code Playgroud)
虽然我与瑞摩斯Rusanu,IMO,代码的可维护性(因而可读性,最小惊讶等)胜过其他问题同意除非性能差足够显著以保证否则做.因此,以下查询会失去可读性:
Select ..
From Table
Where StatusId = 87
Run Code Online (Sandbox Code Playgroud)
通常,当我有一个系统相关的值将在代码中引用(可能在名称中按枚举模仿)时,我使用字符串主键来保存它们的表.将此与用户可更改的数据进行对比,其中我通常使用代理键.使用需要输入的主键有助于(尽管不是很完美)向其他开发人员表明该值并不是任意的.
因此,我的"状态"表看起来像:
Create Table Status
(
Code varchar(6) Not Null Primary Key
, ...
)
Select ...
From Table
Where StatusCode = 'Loaded'
Run Code Online (Sandbox Code Playgroud)
这使得查询更具可读性,它不需要连接到Status表,也不需要使用幻数(或guid).使用用户定义的函数,IMO是一种不好的做法.除了性能影响之外,没有开发人员会期望以这种方式使用UDF,因此违反了最不惊讶的标准.你几乎被迫为每个常量值都有一个UDF ; 否则,你传递给函数的是什么:一个名字?一个神奇的价值?如果是名称,您可以将名称保留在表中并直接在查询中使用它.如果一个神奇的价值,你回到原来的问题.