使用动态字段的数据库设计:单个表与多个表 - 许多索引

Str*_*rae 3 database-design design-patterns database-schema

我必须选择将使用动态字段存储内容类型(例如,博客文章,页面,文档,发票,估计等等)的数据库的结构:例如,Estimate内容类型应具有字段title,datetotal price.

然而,在这些田地可以添加矿石去除的时间,所以1年后,Estimate含有类型的notes田地可以有.

这是由着名的CMS(例如drupal)提供的常见任务,但我想知道什么是获得最佳性能和灵活性的最佳方法:例如Drupal用于拥有一个带有basic字段的表(例如title),并且所有辅助字段都是存储在动态创建的子表中,并使用外键链接到主表:

table node
| id | title         | ...
|  1 | First example |
table fields_node_total_price
| id | node_id | value  |
|  1 | 1       | 123.45 |
table fields_node_date
| id | node_id | value    |
|  1 | 1       | 12345677 |
Run Code Online (Sandbox Code Playgroud)

等等..

我的观点是这种方法非常灵活,但很容易陷入性能问题:为了获取文档的所有字段,您必须多次连接表,并且代码本身必须多次迭代才能构建查询(但这不应该是一个问题).

顺便说一句多表是最常用的方法..因此必须有很多缺点.

我在考虑使用单个表会有什么样的不利之处:

| id | title | total_price | date | ec...
Run Code Online (Sandbox Code Playgroud)

我做了一些测试,有5个和50个额外的字段; 单表方法和多表方法之间的性能非常好:单表的速度提高了约50倍.

每次添加一个字段时,都会在表格中添加一列.这种方法会出现什么样的问题?

编辑

让我提供一些细节:

  1. 该应用程序仍处于设计阶段,是对旧应用程序的完全重新设计,其中字段编号是静态的
  2. 我们做了很少的测试来模拟要存储的对象,包括单表方法和多表方法(使用50个字段),结果如下:

时间以秒为单位:

Test                                                            1°          2°          3°          4°          5°          avg
1000 insert single_table                                        8,5687      8,6832      8,7143      8,7977      8,6906      8,69090137389466
1000 select single table LIKE '%key%' on char(250) field        1,5539      1,5540      1,5591      1,5602      1,5564      1,556705142
1000 select single table LIKE '%key%' on char(25) field         0,8848      0,8923      0,8894      0,8919      0,8888      0,889427996
1000 select single table id = $n                                0,2645      0,2620      0,2645      0,2632      0,2636      0,263564462
1000 select single table integer field < $j                     0,8627      0,8759      0,8673      0,8713      0,8767      0,870787334
1000 insert multi_table                                         446,3830    445,2843    440,8151    436,6051    446,0302    443,023531816
1000 select multi table LIKE '%key%' on char(250) field         1,7048      1,6822      1,6817      1,7041      1,6840      1,691367196
1000 select multi table LIKE '%key%' on char(25) field          0,9391      0,9365      0,9382      0,9431      0,9408      0,939536426
1000 select multi table id = $n                                 0,9336      0,9287      0,9349      0,9331      0,9428      0,93460784
1000 select multi table integer field < $j                      2,3366      2,3260      2,3134      2,3342      2,3228      2,326600456
Run Code Online (Sandbox Code Playgroud)

Mr *_*ose 5

可能值得研究NoSQL数据库的可能性.我自己并没有太多使用它们,但鉴于你说你需要"...存储内容类型(例如,博客文章,页面,文档,发票,估算等等)"和动态字段"看起来好像它可能是一种合理的方法.

来自维基百科的文章 ;

...这些数据存储可能不需要固定的表模式,通常避免连接操作,并且通常水平扩展.

通常,NoSQL数据库根据它们存储数据的方式进行分类,并且属于键值存储,BigTable实现,文档存储数据库和图形数据库等类别.

我不是说这是你所有问题的答案,但我肯定会说这值得一看.

关于其他方法,我过去曾使用实体 - 属性 - 值(EAV),虽然性能可能落后于固定架构,但我觉得这是一个必须提供灵活性的折衷方案.架构.

我的情况可能与你的情况有所不同,但如果有任何帮助,我会为你安排.我们将表结构打破成了符合我们情况的逻辑.有一个自然的层次结构,因为有一个父表,其他表的大部分都与之相关.

尽管由于我们正在处理的数据种类繁多,我们需要动态结构,但也有一些固定的结构.因此,对于需要动态结构的每个表,我们创建了一个"主"表和一个"属性"表.

下面是一个例子(SQL Server特定的);

CREATE TABLE [dbo].[ParentTbl](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [KnownCol1] [real] NOT NULL,
        -- Lots of other columns ommitted
    [KnownColn] [real] NULL
)        

CREATE TABLE [dbo].[MainTbl](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [ParentId] [int] NOT NULL, -- FK to ParentTbl.Id
    [KnownCol1] [real] NOT NULL,
        -- Lots of other columns ommitted
    [KnownColn] [real] NULL
) 

CREATE TABLE [dbo].[MainTblAttr](
    [Id] [bigint] IDENTITY(1,1) NOT NULL, -- Note big int to cater for LOTS of records
    [MainId] [int] NOT NULL, --FK to MainTbl.Id
    [AttributeColumn] [nvarchar](255) NOT NULL,
    [AttributeValue] [nvarchar](max) NOT NULL
)
Run Code Online (Sandbox Code Playgroud)

然后,您可以执行PIVOT查询以帮助您获取数据.鉴于您将拥有不同的属性,您需要确定要包含在枢轴中的列.我发现这个例子在我开发解决方案时非常宝贵.但是,SO上有很多例子.只需搜索数据透视动态列.

在我的实例中,拥有父表对于限制我需要遍历的数据量有很大帮助,因为它限制了我需要查看的子记录.在你的情况下可能不是这样,但希望这会给你一些想法.

祝你好运.