【问题标题】:Analyze a scenario performance?分析场景性能?
【发布时间】:2014-01-22 22:17:07
【问题描述】:

我想设计一个动态表单,管理员可以在其中定义每个表单字段。 我设计了 3 个表:用于共享属性的 mainform 表,然后是具有 mainformID 作为外键并定义每个表单字段的 formfield 表 例如:

AutoID | FormID  |  FieldName 
_____________________________
100    | Form1   |  weight
101    | Form1   |  height
102    | Form1   |  color
103    | Form2   |  Size
104    | Form2   |  Type
 ....

至少像下面这样的 formvalues 表:

FormFieldID  |  Value  | UniqueResponseID
___________________________________________
100          |   50px   |   200
101          |   60px   |   200
102          |   Red    |   200

100          |   30px   |   201
101          |   20px   |   201
102          |   Black  |   201


103          |   20x10  |   201
104          |    Y     |   201
....

对于每个表单,我必须加入这 3 个表以捕获所有字段和值。我想知道它是否是设计这种场景的唯一方法?它会降低sql性能吗?或者有什么更快更好的方法吗?

【问题讨论】:

    标签: asp.net sql database performance database-design


    【解决方案1】:

    我喜欢 Branko 的方法,它与我过去创建的元数据模型非常相似,所以这篇文章是对他的扩展。您可能想要添加一个数据类型表,它既适用于本机类型(int、varchar、bit、datetime 等)也适用于您自己的定义(尽管我不认为有必要即兴发挥)。

    因此,Branko 的“价值”列变为:

    value_tinyint tinyint

    value_int int

    value_varchar varchar(xx)

    等等

    使用 datatype_id(可能是 tinyint)作为“mydatatype”表的外键。

    [请原谅没有像 BD 那样漂亮的 ER 图]

    我的数据类型

    datatype_id tinyint

    代码 varchar(16)

    description varchar(64) -- 供参考

    这个扩展应该:

    一个。在读取或写入数据时为您节省大量转换

    b.允许使用一些易于构建的动态 SQL 进行读写操作

    此外(也许这超出了范围),您可能希望存储这些对象的创建/保存顺序,以及基于按钮按下/复选框/单选按钮选择等的条件显示。

    我不会在这里详细介绍,因为我不确定你是否需要这些东西,但如果你需要这些东西,我会不时检查并回复。

    【讨论】:

      【解决方案2】:

      这是EAV 的一种形式,我假设您绝对必须这样做,而不是“静态”设计。

      它会降低 sql 性能吗?

      是的,获取一堆行(在 EAV 下)总是比只获取一个行(在静态设计下)慢。

      或者有没有更快更好的方法?

      不是从逻辑的角度来看,但是可以在物理级别进行重大优化(至少对于查询性能)。具体来说,您可以仔细设计您的键以最小化 I/O(通过将相关数据放在一起),甚至消除 JOIN 本身。

      例如:

      此模型将键通过 FOREIGN KEY 层次结构一直向下迁移到 ATTRIBUTE_VALUE 表。 ATTRIBUTE_VALUE 表中生成的自然复合键使我们能够:

      • 通过单个索引范围扫描 + 表堆访问获取给定表单的所有属性1 em> 在 ATTRIBUTE_VALUE 表上,根本不做任何 JOIN。除此之外,您还可以cluster2 它,消除表堆访问,只剩下索引范围扫描3.

      • 如果您只需要获取特定响应的数据,请更改复合键中字段的顺序,使 RESPONSE_ID 处于前沿。

      • 如果您需要both“按表单”和“按响应”查询,则需要两个索引,此时,我建议将二级索引也用于cover 4 VALUE 字段。

      例如:

      -- Since we haven't used NONCLUSTERED clause, this is a B-tree
      -- that covers all fields. Table heap doesn't exist.
      CREATE TABLE ATTRIBUTE_VALUE (
          FORM_ID INT,
          ATTRIBUTE_NAME VARCHAR(50),
          RESPONSE_ID INT,
          VALUE VARCHAR(50),
          PRIMARY KEY (FORM_ID, ATTRIBUTE_NAME, RESPONSE_ID)
          -- FOREIGN KEYs omitted for brevity.
      );
      
      -- We have included VALUE, so this B-tree covers all fields as well.
      CREATE UNIQUE INDEX ATTRIBUTE_VALUE_IE1 ON
          ATTRIBUTE_VALUE (RESPONSE_ID, FORM_ID, ATTRIBUTE_NAME)
          INCLUDE (VALUE);
      

      1 或特定属性,或特定属性的特定响应。

      2 MS SQL Server 默认集群所有表,除非你指定 NONCLUSTERED 子句。

      3 对聚集和消除 JOIN 的友好性是自然键(相对于代理键)的一些主要优势。但是它们也使表“更胖”,并且不会与 ON UPDATE CASCADE 隔离。我相信在这种特殊情况下利大于弊。有关自然键与代理键的更多信息,请查看here。

      4 幸运的是,MS SQL Server supports 在索引中包含字段仅用于覆盖目的(而不是实际搜索索引)。这使得索引比相同字段上的“正常”索引更精简。

      【讨论】:

        猜你喜欢
        • 2012-12-05
        • 2011-01-01
        • 2014-12-24
        • 1970-01-01
        • 1970-01-01
        • 2014-11-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多