代码之家  ›  专栏  ›  技术社区  ›  StuartLC

SQL中常量的最佳模式?

  •  9
  • StuartLC  · 技术社区  · 14 年前

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

    • 只是硬编码,可能只是“注释”状态

    -- 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';
    

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

    然后

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

    (在我看来,这会在数据库中造成大量污染—在Oracle包包装器中这可能没问题)

    • 以及类似的模式,表值函数以行或列的形式保存常量,这是 CROSS APPLIED 回到 [Table]

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

    4 回复  |  直到 9 年前
        1
  •  14
  •   Remus Rusanu    14 年前

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

    在执行计划中,使用优化器可以在计划生成时检查的常量与使用任何形式的间接寻址(UDF、JOIN、sub-query)之间的结果通常是戏剧性的。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 ...;
    
        2
  •  6
  •   Thomas    14 年前

    虽然我同意Remus Rusanu的观点,但IMO认为,代码的可维护性(以及可读性、最少的惊讶感等)胜过其他关注点,除非性能差异足够大,需要采取其他措施。因此,以下查询失去可读性:

    Select ..
    From Table
    Where StatusId = 87
    

    一般来说,当我有一些依赖于系统的值将在代码中引用时(可能在枚举中通过名称进行模仿),我会对保存这些值的表使用字符串主键。这与我通常使用代理键的用户可变数据形成对比。使用需要entry的主键有助于(尽管不是完美的)向其他开发人员表明这个值不是任意的。

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

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

    价值 ; 否则,您将向函数传递什么:名称?神奇的价值?如果是一个名称,那么最好将该名称保留在表中,并直接在查询中使用它。如果有一个神奇的值,你就回到原来的问题。

        3
  •  3
  •   KuldipMCA    14 年前

    我一直在使用标量函数选项在我们的数据库和它的工作很好,根据我的看法是这个解决方案的最佳方式。

    如果有更多的值与一个项目相关,然后进行查找,就像加载带有静态值的combobox或任何其他控件,那么使用查找是最好的方法。

        4
  •  2
  •   Beth    14 年前

    还可以向状态表中添加更多字段,这些字段充当状态值的唯一标记或分组。