Мы разрабатываем схему базы данных для проекта оптимизации энергосистемы с открытым исходным кодом.
Мы используем модель EAV, потому что хотим, чтобы она была гибкой и позволяла определять проблемы с помощью данных. То есть мы хотим иметь возможность создавать новые классы объектов и связанные с ними параметры данных на лету без необходимости изменять структуру базы данных.
Модель будет реализована в Julia JuMP, и мы будем запрашивать данные через sql. Будет интерфейс с Джулией для доступа к данным через SQL и графический интерфейс в PyQT для просмотра, редактирования, фильтрации данных.
Я дал SQL для текущей схемы ниже.
Идея довольно проста ... и таблица object_class для определения типов объектов. Таблица объектов для определения экземпляров объектов и таблица параметров_определения для определения параметров, которые могут быть связаны с объектами каждого типа, и таблица параметров для определения фактических значений параметров, связанных с экземплярами объектов. Давайте на время забудем об отношениях, чтобы обсуждение было простым. Также я пропустил поля id, которые мы будем включать.
Таблица параметров немного нюансов, потому что наши модели оптимизации являются хронологическими моделями, которые работают с течением времени - поэтому очень часто иметь изменяющиеся во времени данные. Чтобы справиться с этим, мы можем дать «time_pattern» значению данных. Также у наших моделей будут сценарии. В таблице параметров мы можем установить это значение, чтобы указать, что значение параметра применяется к конкретному сценарию. Значение NULL в поле сценария указывает элемент данных «базовый случай».
Теперь самое главное ... член команды решил заменить таблицу параметров полем JSON в таблице объектов. Он убежден, что это лучше, потому что все данные для объекта содержатся в нем, и он избегает нулей, которые мы будем иметь в таблице параметров, когда не указан временной шаблон или сценарий. Однако у меня есть ряд проблем с этим:
1. мы теряем ссылочную целостность между таблицей параметров и таблицей определения параметров. Я знаю, что вы можете ссылаться на поля JSON, но разве это не неэффективно?
2. Может быть некоторая заслуга в идее, если мы предположим, что у каждого объекта может быть список статических параметров (т. Е. Не определен time_pattern или сценарий. Однако, когда они определены, нам нужно иметь вложенные JSON в Поле JSON таблицы объектов. Можем ли мы присоединиться к этому?
3. Из того, что я прочитал, не рекомендуется скрывать какие-либо поля, по которым вы можете запрашивать внутри поля JSON. Это правильно?
4. Можно ли вообще объединять поля внутри вложенных JSON и если это возможно, неэффективно ли это?
5. Даже если вы можете запрашивать и объединять поля, скрытые во вложенном JSON, разве SQL не будет сложным без реальной выгоды?
На первый взгляд, единственное преимущество в том, что вы избавляетесь от одного стола, который может упростить некоторые вызовы. Однако вы просто закапываете данные этой таблицы в поле JSON в другой таблице
Я что-то упустил? Есть ли у этого предложения какие-то преимущества, которые я не получаю?
Так как данные будут массово запрашиваться Джулией, этот элемент, вероятно, не имеет значения, JSON или нет ... но PyQT Gui, где будет фильтрация данных и т. Д. ... код для этого может быть очень сложным?
CREATE TABLE IF NOT EXISTS `db1303628_spine`.`class_category` (
`name` VARCHAR(255) NOT NULL,
`description` VARCHAR(255) NULL DEFAULT NULL,
PRIMARY KEY (`name`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;
-- -----------------------------------------------------
-- Table `db1303628_spine`.`object`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `db1303628_spine`.`object` ;
CREATE TABLE IF NOT EXISTS `db1303628_spine`.`object` (
`class_name` VARCHAR(155) NOT NULL,
`name` VARCHAR(255) NOT NULL,
`description` VARCHAR(255) NULL DEFAULT NULL,
`category_name` VARCHAR(255) NULL DEFAULT NULL,
PRIMARY KEY (`class_name`, `name`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;
-- -----------------------------------------------------
-- Table `db1303628_spine`.`object_category`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `db1303628_spine`.`object_category` ;
CREATE TABLE IF NOT EXISTS `db1303628_spine`.`object_category` (
`object_class_name` VARCHAR(255) NOT NULL,
`name` VARCHAR(255) NOT NULL,
`description` VARCHAR(255) NULL DEFAULT NULL,
PRIMARY KEY (`object_class_name`, `name`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;
-- -----------------------------------------------------
-- Table `db1303628_spine`.`object_class`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `db1303628_spine`.`object_class` ;
CREATE TABLE IF NOT EXISTS `db1303628_spine`.`object_class` (
`name` VARCHAR(255) NOT NULL,
`description` VARCHAR(255) NULL DEFAULT NULL,
`category_name` VARCHAR(155) NULL DEFAULT NULL,
`display_order` INT(11) NULL DEFAULT '99',
`display_icon` INT(11) NULL DEFAULT NULL,
`hidden` TINYINT(1) NULL DEFAULT '0',
PRIMARY KEY (`name`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;
-- -----------------------------------------------------
-- Table `db1303628_spine`.`parameter`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `db1303628_spine`.`parameter` ;
CREATE TABLE IF NOT EXISTS `db1303628_spine`.`parameter` (
`object_name` VARCHAR(155) NOT NULL,
`name` VARCHAR(155) NOT NULL,
`index` TINYINT(2) NULL DEFAULT '1',
`value` VARCHAR(155) NULL DEFAULT NULL,
`expression` VARCHAR(255) NULL DEFAULT NULL,
`time_pattern` VARCHAR(155) NULL DEFAULT NULL,
`deterministic_timeseries_id` VARCHAR(155) NULL DEFAULT NULL,
`stochastic_timeseries_id` VARCHAR(155) NULL DEFAULT NULL,
`stochasticmodel_id` VARCHAR(155) NULL DEFAULT NULL,
`comment` VARCHAR(255) NULL DEFAULT NULL,
PRIMARY KEY (`object_name`, `name`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;
-- -----------------------------------------------------
-- Table `db1303628_spine`.`parameter_definition`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `db1303628_spine`.`parameter_definition` ;
CREATE TABLE IF NOT EXISTS `db1303628_spine`.`parameter_definition` (
`name` VARCHAR(155) NOT NULL,
`description` VARCHAR(155) NULL DEFAULT NULL,
`data_type` VARCHAR(155) NULL DEFAULT 'NUMERIC',
`object_type` VARCHAR(155) NOT NULL,
`object_class_name` VARCHAR(155) NOT NULL,
`CanHaveTimeSeries` TINYINT(1) NULL DEFAULT '0',
`CanHaveTimePattern` TINYINT(1) NULL DEFAULT '1',
`CanBeStochastic` TINYINT(1) NULL DEFAULT '0',
`dafault_value` VARCHAR(155) NULL DEFAULT '0',
`is_madatory` TINYINT(1) NULL DEFAULT '0',
`precision` TINYINT(2) NULL DEFAULT '2',
`minimum_value` DOUBLE(10,4) NULL DEFAULT NULL,
`maximum_value` DOUBLE(10,4) NULL DEFAULT NULL,
PRIMARY KEY (`object_class_name`, `name`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;
-- -----------------------------------------------------
-- Table `db1303628_spine`.`relationship`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `db1303628_spine`.`relationship` ;
CREATE TABLE IF NOT EXISTS `db1303628_spine`.`relationship` (
`class_name` VARCHAR(155) NOT NULL,
`name` VARCHAR(155) NOT NULL,
`parent_object_name` VARCHAR(155) NOT NULL,
`child_object_name` VARCHAR(155) NOT NULL,
PRIMARY KEY (`class_name`, `name`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;
-- -----------------------------------------------------
-- Table `db1303628_spine`.`relationship_class`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `db1303628_spine`.`relationship_class` ;
CREATE TABLE IF NOT EXISTS `db1303628_spine`.`relationship_class` (
`name` VARCHAR(155) NOT NULL,
`parent_class_name` VARCHAR(155) NOT NULL,
`child_class_name` VARCHAR(155) NOT NULL,
`inheritance` VARCHAR(155) NULL DEFAULT NULL,
`hidden` TINYINT(1) NULL DEFAULT '0',
`type` INT(11) NULL DEFAULT NULL,
PRIMARY KEY (`name`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;