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

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

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

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

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

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

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

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

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

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

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

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

Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
0
1
434
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

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

Tagor 01.11.2018 02:48

о да, это также очень удобно для Интернета. Должен был упомянуть об этом. Спасибо

Daniel Farrell 01.11.2018 02:50
Ответ принят как подходящий

In my application there are going to be many types of instructions and new instruction types will be added continuously during the lifetime of the application.

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

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

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

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

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

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

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

Summarized: if you think of a lot of commands to support, regularly changing parameters or kind of commands to support, may advice would be to have one table containing all commands to support. Let your repository pattern check the parameters before adding / updating / executing

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

Tagor 01.11.2018 11:44

Другие вопросы по теме