2009-09-07 14 views
34

一連の構成値をデータベースに格納する必要があります。 2つの列(名前、値)と各ペアの行、または各設定パラメータと1行の列を持つテーブルが格納されていたと考えました。 最初に、設定値を追加するために別の行を追加するだけで済みます.2番目の設定では、テーブルに列を追加する必要があります。私が考慮すべき問題がありますか?他のものより効率的ですか?アプリケーションの設定やアプリケーションオプションの設定に最適なテーブルデザインですか?

答えて

18

設定データの場合は、構成ごとに1行のキー/値構造を使用します。このデータを一度読み込んでキャッシュすると、パフォーマンスに問題はありません。あなたが指摘しているように、設定キーの変更のたびにカラムを追加するには、より多くのメンテナンスが必要です。

SQLは、同じ(同じでなければ同じ)構造化データの任意の大きなセットのモデリングと操作に優れています。設定情報のセットは実際にはそうではありません - あなたは1行のデータを持っているか、まったく無関係なデータの複数の行を持っています。つまり、これをデータストアとして使用しているだけです。私は、SQLデータモデルをスキップし、単純に行くと言う。

+1

+1のキャッシュ。 – APC

3

2列(名前、値)のデザインがはるかに優れていると思います。あなたが言ったように、新しいプロパティを追加する必要がある場合は、新しい行「insert」にするだけです。他のデザイン(1行)では、新しいプロパティの列を追加するためにテーブルスキーマを変更する必要があります。

これは、あなたのプロパティのリストが将来変更されるかどうかによって異なります。

+3

2列のデザインではなく、2行のデザインを意味すると思います。 –

+0

新しいプロパティを追加する機能は、別の列に格納されていてもそれほど難しいものではないと告白する必要があります。アプリケーションのDBスキーマの変更を実稼働環境に手動で移行するのではありませんか? –

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

最高の方法です。テーブルに列を追加するのは大抵だけど、1行のテーブルのポイントは何ですか?

これはSQLには適しているのかどうかわかりませんが、悲しいかな、質問...

10

最初に考慮する必要があるのは、情報を取得する効率について考えをやめることです。まず最初に、どのようにに効果的にを理解するをモデル化し、それからデータをモデル化する方法を見つけ出す

したがって、保存している設定データの性質によって異なります。別々の(名前、値)の組が基本的に無関係な場合は、1行につき1組として保管します。それらが関連している場合は、複数の列を持つスキームを検討することができます。

関連するとはどういう意味ですか?いくつかのキャッシュ設定を考えてみましょう。各キャッシュにはいくつかの属性があります。

  • eviction policy;
  • 有効期限;
  • 最大サイズ。

各キャッシュに名前があるものとします。次の3つの行として、このデータを格納することができ:

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

が、このデータは関連であり、あなたは、多くの場合、一度にすべてを取得する必要があります。その場合、id、name、eviction、expiry、max_sizeという5つのカラムを持つcache_configテーブルを持つことは理にかなっています。

これは私が関連するデータを意味するものです。

0

私は両方の方法を使いましたが、私は2列の方法を好んでいました。各設定の新しい列に戻すことは、コードを変更して新しい設定を追加する必要があることです。

(私が値にアクセスしているときに)設定方法ごとに1列を使用することをお勧めします。これは、構成設定がより明示的に設定されているためです。しかし、その好みは、テーブルに新しい構成を追加することの難しさを測るものではありません。

2列の方法をお勧めします。次に、アクセッサ関数/ sprocを設定して値を取得します。

14

もう1つの考慮事項:各設定パラメータの列で、簡単にバージョンを取得できます。各行はバージョンを表します。

+1

これは非常に興味深いアイデアです! –

0

に依存します。

値が15より小さい場合は、それぞれの列を作成します。

設定の数を定期的に変更する場合や、すべての設定を使用しない場合は、設定ごとに行を作成することを検討します。

それ以外にも、おそらくトスップです。あなたの使用パターンによって異なります。すべての設定を常に取得する必要がある場合は、おそらくそれらを1つの行に入れるのが最も簡単です。

カラムを追加することはあまり難しくありません。プログラムを分かりやすくすると、通常は他のコードを更新する必要はありません。

2

XMLを使用して効率的に設定を保存できます。一部のデータベースでは、値をxmlデータ型として保存し、その特定の列でXQUERYを実行できるPure XML機能をサポートしています。

2つの列名と構成を持つ表を作成します。 XMLデータ型の文字列データ型と構成を持つ名前。新しい構成パラメータの挿入と削除を心配する必要はなく、xmlの新しいタグになります。また、データベースがXMLをサポートしていない場合は、文字列としてXML形式で保存するだけで、その設定を手動で解析したり、いくつかのAPIを効率的に使用したりすることができます。

これは、完全な設定を文字列として保存する代わりに、より良い方法だと思います。

2

ここで私はいつもブログをしますmoved our AppSettings to a Database Table. アプリケーションの開始時に1回だけプルして、簡単な検索のために辞書に格納されるため、パフォーマンスは問題にはなりません。

アプリケーションについて確認が、我々はこれをしなかった重要な理由は、あなたがデベロッパー、テストしている場合の生産値を使用することは不可能である今、個別の行を使用するなど

11

一つの欠点ではありません(アプリケーション)構成設定(またはアプリケーションオプション)ごとに、適切なデータ型の列に設定値を格納できないことがあります。ユーザーが無効なタイプのデータを入力できるか?それはあなたのアプリケーションに関係していますか?

別々の列を使用する利点の1つは、DB自体のコード(ストアドプロシージャや関数など)は、最初に無効な値をチェックする必要がなく、適切なデータ型の値を使用できることです。適切なデータ型

手動でアプリケーションDBへの変更を展開している場合は、EAVのデザインを使用しているならば、はい、非常に新しい構成設定を展開する少し簡単ですが、実際のための貯蓄ものです:

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

ALTER TABLE Options ADD NewConfigurationSetting some_datatype 

UPDATE Options 
SET NewConfigurationSetting = NewConfigurationSettingValue 
1

私は(別名、間違ったデータ・タイプ)文字列に文字列以外の値を入れて軽蔑します。 (@Kenny Evittは、上記説明したよう)

だから私は垂直になり、正しいデータ型を扱うこと以下の代替を考え出しますよ。

私は実際にお金とスモールマネーを使用していません。しかし、私はそれらを完全性のために含めました。 注意、

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

参照しかし、以下のほとんどのものをカバーしてそこにいくつかの他のデータ型があります。

正直言って、文字列(varchar(1024))、int、smallint、bit ...の99%を使用しています。

これは完璧ではありません。別名、ヌルタプルがたくさんあります。しかし、あなたはこれらを一度しか取得しないので、設定オブジェクト(私の世界ではC#)へのマッピングは難しくありません。

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()),  

ことが多すぎる、とあなたはすべての値のための「文字列」を使うことに決めている場合さて、その後、ここでいくつかの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 */ 

は今、大きな遠くそれを取って、あなたはまだ正しいデータ型と強く型付けされたDOTNETオブジェクトを作成し、下図のように強力なオブジェクトにあなたのDataReader /データセットを変換することができます。

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

上記のSettingDataTypeメソッドを使用しても、C#クラス(またはその他の言語)を使用できます。 "マッピング"コードはちょっとした作業が必要です。

Outvotedされていないときは、上記のようにSettingDataTypeクラスとC#クラスを使用します。

0

「ベスト」は文脈によってまったく異なります。このデータはどのように使用されますか?

1組の構成設定を保存して検索するだけであれば、最初はリレーショナルデータベースを使用することに疑問があります。ファイルシステムの設定ファイルよりも明白な利点はありません。設定ファイルのバージョン管理を簡単に使用することはできません。"DEV"、 "TEST"、 "PRODUCTION"環境)では、データベースを変更するためのGUIが必要になります(ああ、まずデータベースにどのように接続しますか?)。

アプリケーションが設定全体を「理由づけ」する必要がある場合(例:マルチテナントソリューションがあり、現在のシステムに基づいてアプリケーションを動的に設定する必要がある場合は、構成ファイルをデータベースに保存して、アプリケーションがドキュメントを保存/取得できるようにするメタデータを保存することをお勧めします。異なるデータベースエンジンには、テキスト文書を格納するためのさまざまなソリューションがあります。例えば、マルチテナントシステムであなたが持つかもしれない:

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

これは、3月3日後に有効だった、クライアント1用のファイルを取得することができ、そしてどんなアプリケーションのニーズを行うだろう。

アプリケーションが、独自のエンティティとして構成するのではなく、構成の内容を検討する必要がある場合は、別の問題があります。あなたが提案する「名前/値」ソリューションは、エンティティ/属性/値(EAV)としても知られており、利点と欠点を議論するlotsofSOquestionsがあります。 TL; DR:EAVを使用するときは簡単な質問をSQLに変換することは難しいです。

各設定が適切なデータ型の列である場合、データを照会するほうがずっと簡単です。しかし、これは非常に「広い」テーブル(ほとんどのアプリケーションには数十から数百もの設定値があります)になり、構成設定を追加するたびにデータベーススキーマが変更されることになります。実用的です。

代わりに、設定値を構造化文書として格納することです(XMLとJSONは広くサポートされています)。これらの形式はデータベースエンジンによって照会できますが、固定スキーマは必要ありません。

関連する問題