SQL中常量的最佳模式?

时间:2010-07-30 10:48:38

标签: sql-server constants maintainability

我已经看到过几种模式用于“克服”SQL Server中缺少常量,但它们似乎都没有满足性能和可读性/可维护性问题。

在下面的示例中,假设我们的表上有一个完整的“状态”分类,选项似乎是:

  • 只是硬编码,可能只是'评论'状态

-- StatusId 87 = Loaded
SELECT ... FROM [Table] WHERE StatusId = 87;
  • 使用状态查找表,然后加入此表,以便WHERE子句引用友好名称。

子查询:

SELECT ... 
FROM [Table] 
WHERE 
  StatusId = (SELECT StatusId FROM TableStatus WHERE StatusName = 'Loaded');

或加入

SELECT ... 
FROM [Table] t INNER JOIN TableStatus ts On t.StatusId = ts.StatusId 
WHERE ts.StatusName = 'Loaded';
  • 定义了一堆返回常量的标量UDF,即

CREATE Function LoadedStatus()
RETURNS INT
AS
 BEGIN
  RETURN 87
 END;

然后

SELECT ... FROM [Table] WHERE StatusId = LoadedStatus();

(IMO会导致数据库中出现大量污染 - 在Oracle软件包中可能没问题)

  • 使用表值函数的类似模式将常量值保存为行或列,CROSS APPLIED返回[Table]

其他SO用户如何解决这个常见问题?

编辑:赏金 - 根据Remus的回答和评论,有没有人在DBProj DDL / Schema脚本中维护$(变量)的最佳实践方法?

4 个答案:

答案 0 :(得分:12)

硬编码。 SQL性能胜过可维护性。

使用优化程序在计划生成时可以检查的常量与使用任何形式的间接(UDF,JOIN,子查询)之间的执行计划的后果通常是戏剧性的。 SQL'编译'是一个非同寻常的过程(在某种意义上说,不像IL代码生成那样'普通')因为结果不仅由编译的语言结构(即查询的实际文本)决定,而且还由通过数据模式(现有索引)这些索引中的实际数据(统计数据)。当使用硬编码值时,优化器可以提供更好的计划,因为它实际上可以根据索引统计信息检查值并获得结果的估计值。

另一个考虑因素是SQL应用程序不仅仅是代码,但是大部分是代码数据。 “重构”SQL程序是......不同的。在C#程序中,可以更改常量或枚举,重新编译并愉快地运行应用程序,在SQL中不能这样做,因为该值可能存在于数据库中的数百万条记录中,并且更改常量值意味着也会更改数据的GB ,当新的操作发生时,经常在线

仅仅因为该值在查询中是硬编码的,并且服务器看到的过程并不一定意味着该值必须在原始项目源代码中进行硬编码。有各种代码生成工具可以解决这个问题。考虑一下像利用sqlcmd scripting variables

这样微不足道的事情

defines.sql

:setvar STATUS_LOADED 87

somesource.sql

:r defines.sql
SELECT ... FROM [Table] WHERE StatusId = $(STATUS_LOADED);

someothersource.sql

:r defines.sql
UPDATE [Table] SET StatusId = $(STATUS_LOADED) WHERE ...;

答案 1 :(得分:6)

虽然我同意国际海事组织Remus Rusanu,代码的可维护性(以及可读性,最不惊讶等)胜过其他问题,除非性能差异足够重要以保证不这样做。因此,以下查询会失去可读性:

Select ..
From Table
Where StatusId = 87

通常,当我有代码中引用的系统相关值(可能是按名称在枚举中模仿)时,我将字符串主键用于保存它们的表。将此与用户可更改的数据进行对比,其中我通常使用代理键。使用需要输入的主键有助于(尽管不是很完美)向其他开发人员表明该值并不是任意的。

因此,我的“状态”表格如下:

Create Table Status
(
    Code varchar(6) Not Null Primary Key
    , ...
)
Select ...
From Table
Where StatusCode = 'Loaded'

这使查询更具可读性,不需要连接到Status表,也不需要使用幻数(或guid)。使用用户定义的函数,IMO是一种不好的做法。除了性能影响之外,没有开发人员会期望以这种方式使用UDF,因此违反了最不惊讶的标准。您几乎被迫为每个常量设置UDF;否则,你传递给函数的是什么:一个名字?一个神奇的价值?如果是名称,您可以将名称保留在表中并直接在查询中使用它。如果是一个神奇的价值,你就回到原来的问题。

答案 2 :(得分:3)

我一直在使用数据库中的标量函数选项,它工作正常,根据我的观点,这是此解决方案的最佳方式。

如果与一个项目相关的更多值然后进行查找,就像加载组合框或任何其他具有静态值的控件一样,那么使用查找是执行此操作的最佳方法。

答案 3 :(得分:2)

您还可以在状态表中添加更多字段,作为状态值的唯一标记或分组。 例如,如果将isLoaded字段添加到状态表中,则记录87可能是唯一具有字段值设置的字段,您可以测试isLoaded字段的值而不是硬编码的87或状态描述。 / p>

相关问题