Подтвердить что ты не робот

Лучший дизайн таблицы для настройки приложения или параметров приложения?

Мне нужно сохранить ряд значений конфигурации в базе данных. Несколько способов, которые я думал о их хранении, - это таблица с двумя колонами (имя, значение) и строка для каждой пары или таблица со столбцом для каждого параметра конфигурации и 1 строка? Сперва мне нужно добавить еще одну строку, чтобы добавить значение конфигурации, а второе мне нужно добавить столбец в таблицу. Есть ли какие-либо проблемы с тем, что я должен принять к рассмотрению? Является ли более эффективным, чем другой?

4b9b3361

Ответ 1

Для данных конфигурации я бы использовал структуру key/value со строкой для каждой записи конфигурации. Вероятно, вы прочитаете эти данные один раз и кешируете его, поэтому производительность не является проблемой. Как вы отмечаете, добавление столбцов каждый раз, когда изменяется набор ключей конфигурации, требует гораздо больше обслуживания.

SQL превосходит при моделировании и манипулировании произвольно большими наборами аналогичных (если не одинаковых) структурированных данных. Набор информации о конфигурации действительно не таков: у вас есть одна строка данных или у вас есть несколько строк абсолютно несвязанных данных. Это говорит о том, что вы просто используете это как хранилище данных. Я говорю пропустить модель данных SQL и простую.

Ответ 2

Еще одно соображение: с столбцом для каждого параметра конфигурации вы можете легко иметь версии. Каждая строка представляет собой версию.

Ответ 3

Одним из недостатков использования отдельной строки для каждого параметра (приложения) конфигурации (или параметра приложения) является то, что вы не можете сохранить значения параметров в столбце с соответствующим типом данных. Могут ли пользователи вводить данные с недопустимым типом? Это относится к вашему приложению?

Одно из преимуществ использования отдельных столбцов заключается в том, что любой код в вашей базе данных (например, хранимые процедуры, функции и т.д.) может использовать значение соответствующего типа данных, не требуя сначала проверки недопустимых значений, а затем преобразования в соответствующий тип данных.

Если вы вручную развертываете изменения в своей прикладной БД, тогда да, если вы используете дизайн EAV, очень немного проще развернуть новые параметры конфигурации, но действительно, что сэкономить на:

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

против

ALTER TABLE Options ADD NewConfigurationSetting some_datatype

UPDATE Options
SET NewConfigurationSetting = NewConfigurationSettingValue

Ответ 4

Первым вопросом, который вы должны рассмотреть, является следующее: перестать думать об эффективности извлечения информации. в первую очередь, выяснить, как эффективно и правильно моделировать данные, а затем (и только потом) выяснить, как это сделать эффективно.

Таким образом, это зависит от характера хранимых конфигурационных данных. Если отдельные (имя, значение) пары в основном не связаны друг с другом, сохраните их как одну строку. Если они связаны, вы можете рассмотреть схему с несколькими столбцами.

Что я имею в виду? Рассмотрим конфигурацию кеша. Каждый кеш имеет несколько атрибутов:

  • политика выселения;
  • время истечения срока действия;
  • максимальный размер.

Предположим, что у каждого кеша есть имя. Вы можете сохранить эти данные в виде трех строк:

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

но эти данные связаны между собой, и вам часто может потребоваться сразу их загрузить. В этом случае имеет смысл иметь таблицу cache_config с пятью столбцами: id, name, eviction, expiry, max_size.

Что я имею в виду по связанным данным.

Ответ 5

Я думаю, что дизайн 2-coumn (имя, значение) намного лучше. Как вы сказали, если вам нужно добавить новое свойство, все, что вам нужно сделать, это "insert" новая строка. Хотя в другом проекте (однострочном) вам нужно изменить схему таблицы, чтобы добавить столбец для нового свойства.

Это, однако, зависит от того, изменится ли ваш список свойств в будущем.

Ответ 6

Эффективное сохранение конфигурации с помощью XML. Некоторая поддержка базы данных Функция чистого XML, в которой вы можете сохранить значение как тип данных xml, и вы можете запустить XQUERY в этом конкретном столбце.

Создайте таблицу с двумя именами столбцов и конфигурацией. имя с строковым типом данных и конфигурацией с типом данных xml, поэтому не нужно беспокоиться о вставке и удалении новых параметров конфигурации, вы просто новый тег в xml. И если база данных не поддерживает XML, просто сохраните ее как строку, но в формате XML, чтобы вы могли анализировать эту конфигурацию вручную или с помощью некоторого API эффективно.

Я думаю, что это было бы лучше, вместо сохранения полной конфигурации в виде строки.

Ответ 7

Здесь я рассказываю о том, когда мы переместили нашу AppSettings в таблицу базы данных. Производительность не является проблемой, потому что она тянет только один раз в начале приложения и хранится в словаре для удобного поиска.

Не уверен в отношении вашего приложения, но важная причина, почему мы это сделали, теперь невозможно использовать значения Production, если вы находитесь в Dev, Test и т.д.

Ответ 8

Я DESPISE помещаю нестроковые значения в строковый столбец (иначе, неверные типы данных). (Как обсуждает @Kenny Evitt)

Итак, я придумал альтернативу , которая идет по вертикали и имеет дело с правильными типами данных.

На самом деле я не использую деньги и мелкие деньги. Но я включил их для полноты. Обратите внимание, что есть несколько других типов данных

см

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

Но нижняя часть охватывает большинство вещей.

честно говоря, я использую только строку (varchar (1024)), int, smallint и бит... 99% времени.

Это не идеально. Ака, у тебя много нулевых кортежей. Но поскольку вы только захватываете эти один раз (и кеш), сопоставление с объектом настроек (в С# в моем мире) не сложно.

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/dataset в сильный объект, как показано ниже.

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 выше. Код "mapping" просто нуждается в небольшой дополнительной работе.

Если не отменено, я использую классы SettingDataType и С#, как показано выше.

Ответ 9

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

Лучший способ. Добавление столбца в таблицу обычно отстой, а какая точка таблицы с одной строкой?

Не уверен, что это подходит для SQL, но, увы... вопрос ответил.

Ответ 10

Я использовал оба метода, и я предпочитаю метод с двумя столбцами. Возврат к новому столбцу для каждой конфигурации - это изменение кода для добавления новых параметров.

Я предпочитаю использовать один столбец для каждого метода установки (когда я обращаюсь к значению). Это связано с тем, что настройки конфигурации более явно заданы. Но это предпочтение не учитывает трудности добавления новой конфигурации в таблицу.

Я бы рекомендовал метод с двумя столбцами. Затем настройте функцию доступа /sproc, чтобы получить значения.

Ответ 11

зависит.

Если у вас меньше 15 значений, я бы сделал столбцом для каждого.

Если вы регулярно изменяете количество настроек или часто не используете все настройки, я бы подумал о создании строки для каждой настройки.

Помимо этого, это, вероятно, tossup. Зависит от ваших шаблонов использования. Если вам всегда нужно ухватить все настройки, это, вероятно, быстрее всего будет в одной строке.

Добавление столбцов не слишком сложно, и если вы программируете разумно, вам обычно не нужно обновлять какой-либо другой код.

Ответ 12

"Лучшее" полностью зависит от контекста - как будут использоваться эти данные?

Если все, что вам нужно сделать, это сохранить и получить один набор параметров конфигурации, я бы поставил под вопрос использование реляционной базы данных в первую очередь - он не добавляет очевидной выгоды по сравнению с файлами конфигурации в файловой системе. Вы не можете легко использовать контроль версий для своих конфигурационных файлов, а также управлять различиями в среде (например, "DEV", "TEST" и "ПРОИЗВОДСТВО" ) теперь требуется графический интерфейс для изменения базы данных (о, и как вы подключаетесь к база данных в первую очередь?).

Если вашему приложению необходимо "обосновать" конфигурацию в целом - например, если у вас есть решение для нескольких арендаторов и вам необходимо динамически настроить приложение на основе текущей системы - я бы предложил сохранить файлы конфигурации в виде текстового документа в вашей базе данных, с метаданными, которые позволяют приложению хранить/извлекать документ, Различные базы данных имеют разные решения для хранения текстовых документов. Например, в многоуровневой системе вы можете:

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

Это позволит вам получить файл для клиента 1, который был действителен после 3 марта, и выполнять все, что требуется приложению.

Если вашему приложению необходимо обосновать содержимое конфигурации, а не настройку как самостоятельную сущность, у вас есть другая проблема. Предлагаемое вами решение "имя/значение" также называется Entity/Attribute/Value (EAV), и есть лоты fooobar.com/info/162252/... questions обсуждать преимущества и недостатки. TL; DR: трудно конвертировать даже простые вопросы в SQL при использовании EAV.

Гораздо проще запрашивать данные, если каждый параметр конфигурации является столбцом с соответствующим типом данных. Но это означает, что у вас заканчивается очень "широкая" таблица (большинство приложений имеют десятки или даже сотни значений конфигурации), и каждый раз, когда вы хотите добавить параметр конфигурации, вы в конечном итоге модифицируете схему базы данных, Практически.

Альтернативой, таким образом, является сохранение значений конфигурации в виде структурированного документа - XML ​​и JSON широко поддерживаются. Эти форматы могут запрашиваться механизмом базы данных, но не требуют фиксированной схемы.