Как лучше всего сохранять ответы на вопросы с разными типами данных в MYSQL? - PullRequest
0 голосов
/ 19 февраля 2020

ОБНОВЛЕНИЕ: часть 1 - начало:

Мы хотим получить данные наших клиентов, но какие именно данные? они не указаны! на самом деле мы хотим иметь динамическое приложение c, которое администратор может определять новые вопросы (он может установить тип данных ответа, длину и другие правила), а также он может деактивировать старые вопросы!

(я не хочу использовать схему EAV, но не могу найти альтернативный путь)

ОБНОВЛЕНИЕ: часть 1 - конец:

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

Пример:

идентификатор вопроса 1 : как вас зовут? ответ : Джон (varchar)

идентификатор вопроса 2 : сколько вам лет? ответ : 25 (целое число)

ID вопроса 3 : сколько ваша зарплата в час? ответ : 30,65 (десятичное число)

идентификатор вопроса 4 : опишите себя? ответ : Я так добр ... (текст)

ОБНОВЛЕНИЕ: часть 2 - начало:

чтобы сохранить ответы, мне приходит в голову 3 варианта:

ОБНОВЛЕНИЕ: часть 2 - конец:

  1. создать такую ​​таблицу (проект схемы EAV) :
    Table profile_answers
    id int [pk, increment]
    question_id int
    profile_id int
    answer text

, как вы видите, я сохранил все ответы как текст ! Я знаю, что это работает, но так ли это лучше? на самом деле это приложение будет иметь миллионы ответов, и мы хотим проанализировать ответы по машинам (например: получить клиентов среднего возраста, жениться на клиентах, клиентов с зарплатой> 30,52 и т. д. c) , поэтому Я хочу реализовать способ с лучшей производительностью !

создайте таблицу, подобную этой (схема EAV):
Table answers
id int [pk, increment]
question_id int
profile_id int
integer_value int
decimal_value decimal
varchar_value varchar
boolean_value boolean
longtext_value longtext

Теперь я могу сохранить данные в соответствующем поле и поместить NULL в другие поля ( Тип данных ответа будет определен при определении вопроса)

Например:

question ID 1 : what is you name? answer: John (varchar)

id 1
profile_question_id 1
profile_id 1
integer_value NULL
decimal_value NULL
varchar_value John
boolean_value NULL
longtext_value NULL

 ----------------
question ID 2 : how old are you? answer: 25 (integer)

id 2
profile_question_id 2
profile_id 1
integer_value 25 
decimal_value NULL
varchar_value NULL
boolean_value NULL
longtext_value NULL

 ----------------
question ID 3 : how much is your salary per hour? answer: 30.65 (decimal)

id 3
profile_question_id 3
profile_id 1
integer_value NULL
decimal_value 30.65
varchar_value NULL
boolean_value NULL
longtext_value NULL

ОБНОВЛЕНИЕ: часть 3 - начало:

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

ОБНОВЛЕНИЕ: часть 3 - конец:

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

Ответы [ 4 ]

1 голос
/ 23 февраля 2020

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

EAV выглядит как обходной путь - и он действительно позволяет хранить данные , Но запросить его очень быстро становится практически невозможно - представьте себе, что вы пытаетесь найти всех клиентов старше 32 лет, которые зарабатывают от 20 до 30 тысяч, и которые выходят замуж. Использование соответствующего типа данных немного поможет, но ваши запросы быстро станут чрезвычайно сложными и, и их невозможно будет оптимизировать.

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

Я бы смоделировал свою систему, используя основные понятия как реляционные сущности (клиент, тест, вопрос), и сохранил ответы как JSON в MySQL.

1 голос
/ 19 февраля 2020

Non-EAV

Для чего нужен тип данных? Пользователь набрал Ответ в виде строки ; он не указал тип данных, не так ли? Это позволяет избежать EAV - просто хранить строки. В этот момент question может быть просто столбцом TEXT в одной таблице. И answer столбец в другой таблице, такой как profile_answers, который вы предложили.

Что касается запросов типа "получение среднего возраста клиентов, вступление в брак клиентов, клиентов с зарплатой> 30,52", вы застряли с таблицей сканирования, будь то EAV или нет. Подход, не связанный с EAV, будет более эффективным, поскольку для получения значения go требуется меньше переходов.

У вас есть таблица Customers; по одной строке на каждого клиента с датой рождения в виде столбца. Средний возраст подразумевает чтение этой колонки и выполнение простых арифметических операций c. То же самое касается семейного положения и заработной платы.

Другими словами, пользовательский интерфейс имеет <form>, который запрашивает «информацию о клиенте». (И другие формы, которые спрашивают о других вещах.) Затем ответы для одного клиента попадают прямо в таблицу, предназначенную специально для информации о клиенте.

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

EAV

Если вы придерживаетесь 5 типов данных, у вас возникают следующие сложные вопросы: насколько точна ваша DECIMAL? Если вопрос «Каково значение пи», то как вы справляетесь с этим разнообразием: 3.14, 3.1416, 3.14159, 3.14159265358979, 22/7, «около 3.14» и т. Д. c? Только VARCHAR(...) или TEXT обрабатывает их.

Что вы имели в виду под «(например: получение клиентов среднего возраста, вступление в брак клиентов, клиентов с зарплатой> 30,52 и т. Д. c)»? Если вы имеете в виду, что пользователь набрал «30,52», то он прекрасно работает, чтобы поместить это в столбец TEXT и сгенерировать запрос

with salary > "30.52"

То есть, число чисел c может быть передано в запросы в виде строк; тип данных не должен совпадать. (Однако «22/7» будет рассматриваться как 22, а «около 3,14» будет сравниваться как 0).

Миллионы строк - Будете ли вы просматривать все из них одновременно? Очень часто? Если у вас есть 50 учеников, которые отвечают на 40 вопросов, это означает, что вы можете ответить на вопросы и ответы от 2000 до go за один раз; не миллионы.

0 голосов
/ 19 февраля 2020

Наличие значений NULL никогда не является хорошей практикой. В пункте 2. у вас есть 8 столбцов, и 4 из них имеют значение NULL. Добавление столбца для каждого типа данных ответов является плохой практикой.

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

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

У меня был опыт работы с опросами и формами. У нас должны быть правила для условного показа страницы, вопроса ... Мы много обсуждали, и у меня были проблемы с тем, чтобы убедить команду, что мы должны перейти на JSON или что-то в этом роде (НЕТ SQL). База данных отношений не предназначена для решения такого рода проблем.

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

0 голосов
/ 19 февраля 2020

В соответствии с официальной MySQL документацией о Требованиях к хранению типа строки для типа данных TEXT требуется L + 2 байта, где L - длина строки. Таким образом, если дан ответ с цифрой c значение 100, он будет использовать 5 байтов.

Принимая во внимание, что согласно записи в документации о Numeri c Требования к типу хранилища те же цифры c значение (100) будет использовать только один байт при использовании типа данных TINYINT (макс. 255) или 2 байта при использовании типа SMALLINT (макс. 65535)

Итак, если вы храните большое количество строк в вашей таблице хранилище может быть в 5 раз больше для значений меньше 256 при сохранении в формате TEXT.

При более высоких значениях размер хранилища становится намного больше:

60000 при TEXT = 7 байт 60000 при SMALLINT = 2 байта

Я бы порекомендовал вам реструктурировать вашу модель данных так, чтобы что данные хранятся с правильным типом. Это также обеспечит более производительную индексацию, функции String / Numeri c будут работать правильно, а компоненты уровня абстракции уровня приложения, такие как Doctrine, будут отображаться на правильный тип языка в PHP, et c.

Вот хорошая статья об оптимизации MySQL дизайна модели данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...