Детализация данных в реляционной базе данных

0

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

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

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

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

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

Изображение 174551

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

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

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

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

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

Теги:
entity-framework
relational-database
entity

2 ответа

2
Лучший ответ

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

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

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

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

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

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

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 команду, включая 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
    Спасибо за исчерпывающий ответ, который также включает, как выполнить инструкцию. Вид инструкции не изменится после того, как он будет введен, формат аргументов всегда останется неизменным для этого типа инструкции. Это больше о поддержке новых типов команд легко. Но все же я собираюсь последовать вашему совету. В моем случае лучше всего не разделять типы команд в разных таблицах.
1

Любая модель функционирует, когда использование достаточно мало. Но когда использование является существенным, 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 не является ограничивающим фактором. В противном случае вы можете объединить их во время выполнения. Это кажется мне неуклюжим, но хранит переменные данные в строках и позволяет запрашивать данные на стороне сервера.

  • 0
    Спасибо за исчерпывающий ответ, я просто смотрел на тип данных JSON для переменной args. Кажется, это было бы хорошо для моего варианта использования из-за динамического характера данных. Использование первого параметра также позволяет получить хорошее отображение между таблицей базы данных и строкой JSON, полученной в остальных API.
  • 0
    о да, это также очень дружественный к сети. Должен был упомянуть это. Спасибо

Ещё вопросы

Сообщество Overcoder
Наверх
Меню