2009-09-07 23 views
34

Tôi cần lưu trữ một loạt các giá trị cấu hình trong cơ sở dữ liệu. Một vài cách tôi nghĩ để lưu trữ chúng là: một bảng với 2 colums (tên, giá trị) và một hàng cho mỗi cặp, hoặc một bảng với một cột cho mỗi tham số cấu hình và 1 hàng? Với lần đầu tiên, tôi chỉ cần thêm một hàng khác để thêm giá trị cấu hình, thứ hai tôi cần thêm cột vào bảng. Có vấn đề gì với tôi nên xem xét không? Là một trong những hiệu quả hơn khác?Thiết kế bảng tốt nhất cho cấu hình ứng dụng hoặc cài đặt tùy chọn ứng dụng?

Trả lời

18

Đối với dữ liệu cấu hình, tôi muốn sử dụng cấu trúc khóa/giá trị với một hàng cho mỗi mục nhập cấu hình. Bạn có thể đọc dữ liệu này một lần và lưu vào bộ nhớ cache, vì vậy hiệu suất không phải là vấn đề. Như bạn đã chỉ ra, việc thêm các cột mỗi khi tập hợp các thay đổi của các phím cấu hình đòi hỏi phải bảo trì nhiều hơn.

SQL trội trong việc lập mô hình và thao tác các tập hợp lớn tùy ý tương tự (nếu không giống nhau) dữ liệu có cấu trúc. Một tập hợp thông tin cấu hình thực sự không phải là - bạn đã có một hàng dữ liệu HOẶC bạn có nhiều hàng dữ liệu hoàn toàn không liên quan. Điều đó nói rằng bạn chỉ sử dụng nó như một kho dữ liệu. Tôi nói bỏ qua mô hình dữ liệu SQL và đi đơn giản.

+1

+1 để lưu vào bộ nhớ cache. – APC

3

Tôi nghĩ thiết kế 2 cột (tên, giá trị) tốt hơn nhiều. Như bạn đã nói, nếu bạn cần thêm thuộc tính mới, tất cả những gì bạn cần làm là "insert" hàng mới. Trong khi ở thiết kế khác (một hàng), bạn cần thay đổi lược đồ bảng để thêm một cột cho thuộc tính mới.

Điều này, tuy nhiên, tùy thuộc vào việc danh sách thuộc tính của bạn sẽ thay đổi trong tương lai hay không.

+3

Tôi nghĩ bạn có nghĩa là thiết kế 2 cột chứ không phải "2 hàng". –

+0

Tôi phải thú nhận rằng khả năng thêm thuộc tính mới không được khó khăn ngay cả khi được lưu trữ trong một cột riêng biệt. Bạn không di chuyển các thay đổi lược đồ DB cho ứng dụng của mình sang môi trường sản xuất bằng tay, phải không? –

0
CREATE TABLE Configuration (
    Name ..., 
    Value ..., 
); 

Cách tốt nhất. Thêm một cột vào một bảng thường hút, và điểm của một bảng với một hàng là gì?

Không chắc chắn điều này là thích hợp cho SQL, nhưng than ôi ... câu hỏi đã được trả lời.

10

Vấn đề đầu tiên bạn nên cân nhắc là: dừng suy nghĩ về hiệu quả truy xuất thông tin. đầu tiên và quan trọng nhất, tìm hiểu cách hiệu quảchính xác mô hình dữ liệu và sau đó (và chỉ sau đó) tìm hiểu cách thực hiện hiệu quả.

Vì vậy, nó phụ thuộc vào bản chất của dữ liệu cấu hình bạn đang lưu trữ. Nếu các cặp riêng biệt (tên, giá trị) về cơ bản không liên quan thì lưu trữ nó thành một hàng trên mỗi hàng. Nếu chúng có liên quan thì bạn có thể muốn xem xét một lược đồ có nhiều cột.

Tôi có ý gì khi liên quan? Hãy xem xét một số cấu hình bộ nhớ cache. Mỗi bộ nhớ cache có một số thuộc tính:

  • chính sách trục xuất;
  • thời gian hết hạn;
  • kích thước tối đa.

Giả sử mỗi bộ nhớ cache có tên. Bạn có thể lưu trữ dữ liệu này là ba hàng:

  • <name>_EVICTION
  • <name>_EXPIRY
  • <name>_MAX_SIZE

nhưng dữ liệu này là liên quan và bạn thường có thể cần phải lấy tất cả chúng cùng một lúc. Trong trường hợp đó, bạn có thể có một bảng cache_config với năm cột: id, name, eviction, expiry, max_size.

Đó là ý nghĩa của dữ liệu liên quan.

0

Tôi đã sử dụng cả hai phương pháp và tôi thích phương pháp 2 cột. Việc rút về cột mới cho mỗi cấu hình là bạn cần thay đổi mã để thêm cài đặt mới.

Tôi thích sử dụng phương pháp Một cột cho mỗi cài đặt (khi tôi truy cập giá trị). Điều này là do cài đặt cấu hình được đặt rõ ràng hơn. Nhưng ưu tiên đó không vượt quá khó khăn khi thêm cấu hình mới vào bảng.

Tôi muốn giới thiệu phương pháp 2 cột. Sau đó, thiết lập một hàm accessor/sproc để nhận các giá trị.

14

Một xem xét thêm: với một cột cho mỗi thông số cấu hình, bạn có thể dễ dàng có phiên bản. Mỗi hàng đại diện cho một phiên bản.

+1

Đây là một ý tưởng rất thú vị! –

0

phụ thuộc.

Nếu bạn có ít hơn 15 giá trị, tôi sẽ tạo cột cho mỗi giá trị.

Nếu bạn thay đổi số lượng cài đặt thường xuyên hoặc nếu bạn thường không sử dụng tất cả các cài đặt, tôi sẽ xem xét thực hiện một hàng cho mỗi cài đặt.

Ngoài ra, đó có thể là một sự quăng lên. Phụ thuộc vào các mẫu sử dụng của bạn. Nếu bạn luôn luôn cần phải lấy tất cả các thiết lập, nó có thể nhanh nhất để có chúng trong một hàng.

Thêm cột không quá khó, và nếu bạn lập trình hợp lý, bạn thường không phải cập nhật bất kỳ mã nào khác của bạn.

2

Bạn có thể lưu cấu hình hiệu quả bằng XML. Một số cơ sở dữ liệu hỗ trợ tính năng Pure XML trong đó bạn có thể lưu giá trị dưới dạng kiểu dữ liệu xml và bạn có thể chạy XQUERY trên cột cụ thể đó.

Tạo bảng có hai tên cột và cấu hình. tên với kiểu dữ liệu chuỗi và cấu hình với kiểu dữ liệu xml do đó không cần phải lo lắng về việc chèn và xóa các tham số cấu hình mới, bạn sẽ chỉ là một thẻ mới trong xml. Và nếu cơ sở dữ liệu không hỗ trợ XML thì chỉ cần lưu nó dưới dạng một chuỗi nhưng ở định dạng XML để bạn có thể phân tích cú pháp cấu hình đó theo cách thủ công hoặc sử dụng một số API hiệu quả.

Tôi nghĩ đây sẽ là cách tốt hơn thay vì lưu trữ cấu hình hoàn chỉnh dưới dạng chuỗi.

2

Ở đây tôi viết blog về thời điểm chúng tôi moved our AppSettings to a Database Table. Hiệu suất không phải là vấn đề vì nó chỉ được kéo một lần khi bắt đầu ứng dụng và được lưu trữ trong từ điển để dễ tra cứu.

Không chắc về ứng dụng của bạn, nhưng lý do quan trọng tại sao chúng tôi đã làm điều này bây giờ là nó không thể được sử dụng các giá trị sản xuất nếu bạn đang ở trong Dev, Test, vv

11

Một bất lợi của việc sử dụng một hàng riêng biệt cho mỗi thiết lập cấu hình (ứng dụng) (hoặc tùy chọn ứng dụng) là bạn không thể lưu trữ các giá trị cài đặt trong một cột với một kiểu dữ liệu thích hợp. Người dùng có thể nhập dữ liệu với loại không hợp lệ không? Điều đó có liên quan đến ứng dụng của bạn không?Một lợi ích của việc sử dụng các cột riêng biệt là bất kỳ mã nào trong chính DB của bạn (ví dụ: thủ tục, chức năng được lưu trữ, v.v.) có thể sử dụng giá trị của kiểu dữ liệu thích hợp mà không cần kiểm tra các giá trị không hợp lệ và sau đó chuyển đổi thành loại dữ liệu thích hợp.

Nếu bạn đang tự triển khai những thay đổi để ứng dụng của bạn DB, sau đó có nếu bạn đang sử dụng một thiết kế EAV nó được rất hơi dễ dàng hơn để triển khai thiết lập cấu hình mới, nhưng các khoản tiết kiệm cho thực sự là những gì:

INSERT Options (ConfigurationSetting, Value) 
VALUES ('NewConfigurationSetting', NewConfigurationSettingValue) 

so:

ALTER TABLE Options ADD NewConfigurationSetting some_datatype 

UPDATE Options 
SET NewConfigurationSetting = NewConfigurationSettingValue 
1

tôi khinh đặt giá trị không theo chuỗi trong một chuỗi cột (hay còn gọi là, không chính xác dữ liệu-loại). (Như @Kenny Evitt thảo luận ở trên)

Vì vậy, tôi đưa ra dưới đây thay thế mà đi dọc VÀ thỏa thuận với kiểu dữ liệu chính xác.

Tôi không thực sự sử dụng tiền và tiền nhỏ. Nhưng tôi đã bao gồm chúng để hoàn thành. Lưu ý, có một vài kiểu dữ liệu khác ra khỏi đó

https://msdn.microsoft.com/en-us/library/ms187752.aspx?f=255&MSPPError=-2147217396

thấy Nhưng bên dưới bao gồm hầu hết mọi thứ.

thành thật mà nói, tôi chỉ sử dụng chuỗi (varchar (1024)), int, smallint và bit ... 99% thời gian.

Nó không hoàn hảo. Aka, bạn có rất nhiều tuple null. Nhưng kể từ khi bạn chỉ lấy một lần (và bộ nhớ cache), ánh xạ tới một đối tượng cài đặt (trong C# trong thế giới của tôi) không phải là khó khăn.

CREATE TABLE [dbo].[SystemSetting](
[SystemSettingId] [int] IDENTITY NOT NULL, 

[SettingKeyName] [nvarchar](64) NOT NULL, 
[SettingDataType] [nvarchar](64) NOT NULL, /* store the datatype as string here */ 

[SettingValueBigInt] bigint NULL, 
[SettingValueNumeric] numeric NULL, 
[SettingValueSmallInt] smallint NULL, 
[SettingValueDecimal] decimal NULL, 
[SettingValueSmallMoney] smallmoney NULL, 
[SettingValueInt] int NULL, 
[SettingValueTinyInt] tinyint NULL, 
[SettingValueMoney] money NULL, 
[SettingValueFloat] float NULL, 
[SettingValueReal] real NULL, 
[SettingValueDate] date NULL, 
[SettingValueDateTimeOffSet] datetimeoffset NULL, 
[SettingValueDateTime2] datetime2 NULL, 
[SettingValueSmallDateTime] smalldatetime NULL, 
[SettingValueDateTime] datetime NULL, 
[SettingValueTime] time NULL, 
[SettingValueVarChar] varchar(1024) NULL, 
[SettingValueChar] char NULL, 

[InsertDate] [datetime] NOT NULL DEFAULT (GETDATE()),    
[InsertedBy] [nvarchar](50) NOT NULL DEFAULT (SUSER_SNAME()),  
[LastUpdated] [datetime] NOT NULL DEFAULT (GETDATE()),    
[LastUpdatedBy] [nvarchar](50) NOT NULL DEFAULT (SUSER_SNAME()),  

)

Bây giờ, nếu đó là quá nhiều, và bạn quyết tâm sử dụng "dây" cho tất cả các giá trị, thì đây là một số DDL.

DROP TABLE [dbo].[SystemSetting] 
DROP TABLE [dbo].[SystemSettingCategory] 

CREATE TABLE [dbo].[SystemSettingCategory] (
    [SystemSettingCategoryId] [int] NOT NULL, 
    [SystemSettingCategoryName] [nvarchar](64) NOT NULL, 
    [InsertDate] [datetime] NOT NULL DEFAULT (GETDATE()),    
    [InsertedBy] [nvarchar](50) NOT NULL DEFAULT (SUSER_SNAME()),  
    [LastUpdated] [datetime] NOT NULL DEFAULT (GETDATE()),    
    [LastUpdatedBy] [nvarchar](50) NOT NULL DEFAULT (SUSER_SNAME()),  
    CONSTRAINT [PK_SystemSettingCategory] PRIMARY KEY CLUSTERED ([SystemSettingCategoryId] ASC), 
    CONSTRAINT UQ_SystemSettingCategoryName UNIQUE NONCLUSTERED ([SystemSettingCategoryName]) 
) 




CREATE TABLE [dbo].[SystemSetting] (
    [SystemSettingId] [int] NOT NULL, 
    [SystemSettingCategoryId] INT NOT NULL,  /* FK to [SystemSettingCategory], not shown here */ 
    [SettingKeyName] [nvarchar](64) NOT NULL, 
    [SettingValue] nvarchar(1024) NULL, 
    [InsertDate] [datetime] NOT NULL DEFAULT (GETDATE()),    
    [InsertedBy] [nvarchar](50) NOT NULL DEFAULT (SUSER_SNAME()),  
    [LastUpdated] [datetime] NOT NULL DEFAULT (GETDATE()),    
    [LastUpdatedBy] [nvarchar](50) NOT NULL DEFAULT (SUSER_SNAME()),  
    CONSTRAINT [PK_SystemSetting] PRIMARY KEY CLUSTERED ([SystemSettingId] ASC), 
    CONSTRAINT FK_SystemSettingCategory_SystemSettingCategoryId foreign key ([SystemSettingCategoryId]) references [SystemSettingCategory] ([SystemSettingCategoryId]), 
    CONSTRAINT UQ_SystemSettingCategoryId_SettingKeyName UNIQUE NONCLUSTERED ([SystemSettingCategoryId] , [SettingKeyName]) 
) 



INSERT INTO [dbo].[SystemSettingCategory] ([SystemSettingCategoryId] , [SystemSettingCategoryName]) 
select 101 , 'EmployeeSettings' UNION ALL select 201, 'StopLightSettings' 

INSERT INTO [dbo].[SystemSetting] ([SystemSettingId] , [SystemSettingCategoryId] , [SettingKeyName] , [SettingValue]) 
      select 1001 , 101 , 'MininumAgeRequirementMonths' , convert(varchar(16) , (12 * 18)) 
UNION ALL select 1002 , 101 , 'MininumExperienceMonths' , convert(varchar(8) , 24) 
UNION ALL select 2001 , 201 , 'RedLightPosition' , 'top' 
UNION ALL select 2002 , 201 , 'YellowLightPosition' , 'middle' 
UNION ALL select 2003 , 201 , 'GreenLightPosition' , 'bottom' 

/* should fail */ 
/* start 
INSERT INTO [dbo].[SystemSettingCategory] ([SystemSettingCategoryId] , [SystemSettingCategoryName]) 
select 3333 , 'EmployeeSettings' 
INSERT INTO [dbo].[SystemSettingCategory] ([SystemSettingCategoryId] , [SystemSettingCategoryName]) 
select 101 , 'xxxxxxxxxxxxxx' 
INSERT INTO [dbo].[SystemSetting] ([SystemSettingId] , [SystemSettingCategoryId] , [SettingKeyName] , [SettingValue]) 
      select 5555 , 101 , 'MininumAgeRequirementMonths' , 555 
INSERT INTO [dbo].[SystemSetting] ([SystemSettingId] , [SystemSettingCategoryId] , [SettingKeyName] , [SettingValue]) 
      select 1001 , 101 , 'yyyyyyyyyyyyyy' , 777 
INSERT INTO [dbo].[SystemSetting] ([SystemSettingId] , [SystemSettingCategoryId] , [SettingKeyName] , [SettingValue]) 
      select 5555 , 555 , 'Bad FK' , 555 
end */ 


Select * from [dbo].[SystemSetting] where [SystemSettingCategoryId] = 101 /* employee related */ 
Select * from [dbo].[SystemSetting] where [SystemSettingCategoryId] = 201 /* StopLightSettings related */ 

Bây giờ, lấy nó xa hơn một lớn, bạn vẫn có thể tạo các đối tượng DotNet đã gõ mạnh với các kiểu dữ liệu chính xác, và sau đó chuyển đổi datareader bạn/tập dữ liệu vào đối tượng mạnh mẽ như bên dưới.

public class EmployeeSettings 
{ 
    public Int16 MininumAgeRequirementMonths { get; set; } 
    public Int16 MininumExperienceMonths{ get; set; } 
} 


public class StopLightSettings 
{ 
    public string RedLightPosition { get; set; } 
    public string YellowLightPosition { get; set; } 
    public string GreenLightPosition { get; set; } 
} 

Bạn vẫn có thể thực hiện các lớp C# (hoặc bất kỳ ngôn ngữ nào) ........ và sử dụng phương pháp SettingDataType ở trên. Mã "ánh xạ" chỉ cần thêm một chút công việc.

Khi không được bỏ qua, tôi sử dụng lớp SettingDataType và C# như đã thấy ở trên.

0

"Tốt nhất" phụ thuộc hoàn toàn vào ngữ cảnh - dữ liệu này sẽ được sử dụng như thế nào?

Nếu tất cả những gì bạn cần làm là lưu trữ và lấy một bộ cài đặt cấu hình đơn lẻ, tôi sẽ đặt câu hỏi về việc sử dụng cơ sở dữ liệu quan hệ ngay từ đầu. Bạn không thể dễ dàng sử dụng kiểm soát phiên bản cho tệp cấu hình và quản lý sự khác biệt về môi trường (ví dụ:Môi trường "DEV", "TEST" và "PRODUCTION" hiện yêu cầu GUI để sửa đổi cơ sở dữ liệu (oh, và làm cách nào để bạn kết nối với cơ sở dữ liệu ở vị trí đầu tiên?).

Nếu ứng dụng của bạn cần "lý do" về toàn bộ cấu hình - ví dụ: nếu bạn có giải pháp nhiều người thuê và cần cấu hình động ứng dụng dựa trên hệ thống hiện tại - tôi khuyên bạn nên lưu trữ tệp cấu hình dưới dạng tài liệu văn bản trong cơ sở dữ liệu của mình, với siêu dữ liệu cho phép ứng dụng lưu trữ/truy xuất tài liệu . Các công cụ cơ sở dữ liệu khác nhau có các giải pháp khác nhau để lưu trữ tài liệu văn bản. Ví dụ, trong một hệ thống multi-tenancy bạn có thể có:

ID client_id valid_from  valid_until configuration_file 
------------------------------------------------------- 
1   1 2016/03/16   NULL  <<DOCUMENT>> 

này sẽ cho phép bạn lấy các tập tin cho khách hàng 1, đó là hợp lệ sau 3 tháng Ba, và làm bất cứ điều gì các nhu cầu ứng dụng.

Nếu ứng dụng của bạn cần phải lý do về nội dung của cấu hình, không phải cấu hình như một thực thể theo đúng nghĩa của nó, bạn có một vấn đề khác. Giải pháp "tên/giá trị" bạn đề xuất còn được gọi là Pháp nhân/Thuộc tính/Giá trị (EAV) và có lotsofSOquestions thảo luận về các lợi ích và hạn chế. TL; DR: thật khó để chuyển đổi các câu hỏi đơn giản thành SQL khi sử dụng EAV.

Việc truy vấn dữ liệu dễ dàng hơn nhiều nếu mỗi cài đặt cấu hình là một cột, với loại dữ liệu thích hợp. Nhưng điều này có nghĩa là bạn kết thúc với một bảng "rộng" (hầu hết các ứng dụng có hàng chục hoặc thậm chí hàng trăm giá trị cấu hình), và mỗi khi bạn muốn thêm một thiết lập cấu hình, bạn sẽ sửa đổi lược đồ cơ sở dữ liệu của mình. t thực tế.

Cách khác, sau đó, là lưu trữ các giá trị cấu hình dưới dạng tài liệu có cấu trúc - XML ​​và JSON được hỗ trợ rộng rãi. Các định dạng này có thể được truy vấn bởi cơ sở dữ liệu, nhưng không yêu cầu lược đồ cố định.

Các vấn đề liên quan