Детализация данных в реляционной базе данных - PullRequest
0 голосов
/ 01 ноября 2018

Я делаю rest-api, получаю список инструкций, которые определенный поток на сервере должен выполнить в течение 24 часов, назовите это ежедневным расписанием. Эта же инструкция выполняется в течение интервала времени:

[
    {
        instructionName: string
        args : [    
            string
            ...         
        ]
        startHh : int
        startMm : int
        endHh : int
        endMm : int
    }   
    ...   
]

Содержание args варьируется в зависимости от instructionName.

Расписание должно сохраняться в MySql. Каждую x секунду поток должен запрашивать у БД текущую инструкцию и выполнять некоторую работу.

Моя проблема в том, что я не уверен, что является лучшим вариантом для хранения списка инструкций в базе данных. На мой взгляд, у меня есть два варианта:

enter image description here

Используя первый подход, все, что мне нужно сделать, это конкатить args в одну строку, а затем непосредственно проанализировать json для объекта DTO и сохранить его, я должен быть осторожен, чтобы не хранить ИнструкцияNames и утверждать, что работающий позже нить не может интерпретировать. Рабочий поток может легко запросить таблицу инструкций и получить текущую инструкцию относительно временного интервала.

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

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

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

Любой вклад приветствуется.

Ответы [ 2 ]

0 голосов
/ 01 ноября 2018

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

Какое решение выбрать, зависит немного от ваших определений много и непрерывно . База данных чрезвычайно хороша для запросов существующих данных. Это довольно хорошо для изменения хранимых данных и добавления новых данных. Это паршиво в изменении структуры базы данных. Поэтому вам следует избегать изменения макета.

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

Даже если много приложений означает 1000 приложений / конфигураций параметров, то таблица на приложение приведет к 1000 таблицам, что довольно нежелательно.

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

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

void ScheduleBackupTask(TimeSpan startTime, TimeSpan stopTime, ... <backup parameters>)
{
     // check the parameter list, to see if they match the parameters of a backup task
     // and create the command
     var command = CreateBackupCommand(<backup parameters>);
     ScheduleCommand(startTime, stopTime, command);
}

void ScheduleCleaningTask(TimeSpan startTime, TimeSpan stopTime, <cleaning parameters>)
{
    // check the parameter list, to see if they match the parameters of a clean task
    // and create the command
    var command = CreateCleanCommand(<cleaning parameters>);
    ScheduleCommand(startTime, stopTime, command);
}

void ScheduleCommand(TimeSpan startTime, TimeSpan stopTime, Command command)
{
      using (var dbContext = new MyDbContext()
      {
           Schedule schedule = new Schedule(startTime, stopTime, command);
           dbContext.Schedules.Add(shedule);
           dbContext.SaveChanges();
      }
}

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

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

Выполнение команды

Очевидно, что запрашивать, какие команды должны быть выполнены, проще и быстрее, используя ваш первый метод. После того, как вы получили команду, включающую commandType, ее легко выполнить:

IEnumerable<Command> commandsToExecute = FetchCommandsToExecute(TimeSpan time);
foreach (Command command in commandsToExecute)
{
     switch (command.CommandType)
     {
          case CommandType.Backup:
               ExecuteBackup(...);
               break;
          case CommandType.Clean:
               ExecuteClean(...);
               break;
     }
}

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

Подведем итог: если вы думаете о большом количестве команд для поддержки, регулярно изменение параметров или вида команд для поддержки, может посоветуете иметь одну таблицу, содержащую все команды для поддержки. Пусть ваш Шаблон репозитория проверяет параметры перед добавлением / обновлением / выполнение

0 голосов
/ 01 ноября 2018

Любая модель работает, когда использование достаточно низкое. Но когда использование является существенным, DDL , например, "ALTER TABLE", для добавления новых аргументов становится, если не чрезмерно, то болезненно дорогим. Нужно сделать так, чтобы схемы таблиц менялись как можно меньше. Таким образом, я бы предпочел ваш первый вариант, если бы мне пришлось выбирать между ними.

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

Если, например, вы захотите ответить на такие вопросы, как «для каких исполнений определенного задания fuelCount было установлено на 3?». Для такого рода вопросов вам нужно будет найти существование fuelCount и его значение по существу в неструктурированной текстовой строке. Для сохранения анализа на сервере потребуется неумелая гимнастика, но перетаскивание каждой строки обратно клиенту mysql для анализа аргументов аналогично несостоятельно для всех, кроме самых маленьких наборов данных.

Другой вариант - использовать mysql json , если ваша версия базы данных поддерживает это. Это позволяет вам моделировать аргументы так, как вы хотите, без необходимости изменять формат таблицы при появлении новых значений. Однако вы должны быть достаточно умны, чтобы старые запросы не нарушались при смене моделей. Поддержка json для mysql означает возможность запрашивать данные в json без необходимости извлекать, анализировать и объединять все отдельные записи в клиенте базы данных, так что это довольно удобная функция. У Postgres также есть это.

Например, вы можете сохранить произвольные данные о команде, которая будет выполняться в столбце runtime JSON, и если вы придерживаетесь некоторых простых правил, вы можете иметь необязательный аргумент для любых аргументов, а также (для пример) переменные окружения, которые также могут потребоваться для программы. Со временем могут возникнуть другие параметры времени выполнения, которые заставят вас добавить больше аргументов к определенным заданиям. тип JSON довольно хорош для этого. Если вы хотите запросить JSON, вы можете. Это позволяет наложить некоторую структуру на данные (например, все аргументы будут находиться в ключе args словаря верхнего уровня), при этом не нужно предварительно определять каждый аргумент, который может быть передан.

Это хорошо иллюстрируется в приведенной выше ссылке, если идея кажется вам хорошей. Вы, похоже, думаете о чем-то вроде json, так что это может быть простым переходом. Это дает дополнительное преимущество, заключающееся в том, что он очень дружественен к Интернету, так как, если вы создаете REST API, вы, вероятно, уже планируете обмениваться JSON.

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

CREATE TABLE args ( instruction_id int, argkey varchar, argval varchar)

и используйте, например, GROUP_CONCAT , чтобы объединить их вместе, если максимальная длина group_concat не является ограничивающим фактором. В противном случае вы все равно можете объединить их во время выполнения. Мне это кажется неуклюжим, но он хранит переменные данные в строках и позволяет запрашивать данные на стороне сервера.

...