Каков наиболее эффективный способ хранения массива целых чисел в столбце MySQL?
У меня есть две таблицы
A:
plant_ID | name.
1 | tree
2 | shrubbery
20 | notashrubbery
B:
area_ID | name | plants
1 | forrest | *needhelphere*
теперь я хочу, чтобы область хранила любое количество растений в определенном порядке, и некоторые растения могли появляться несколько раз: например, 2,20,1,2,2,20,1
Каков наиболее эффективный способ хранения этого массива растений?
Имея в виду, мне нужно сделать так, чтобы, если я выполняю поиск, чтобы найти области с установкой 2, я не получаю области, которые, например, 1,20,232,12,20 (pad с ведущими 0s?) Каким будет запрос для этого?
Если это поможет, допустим, у меня есть база данных не более 99999999 разных растений. И да, этот вопрос не имеет ничего общего с растениями....
Бонусный вопрос
Пришло ли время отходить от MySQL? Есть ли более эффективная БД для управления этим?
Ответы
Ответ 1
Если вы собираетесь искать как по лесу, так и по заводу, звучит так, как будто вы выиграете от полноправного отношения "многие ко многим". Разделите столбец plants
и создайте целую новую таблицу areas_plants
(или все, что вы хотите назвать), чтобы связать две таблицы.
Если в области 1 есть растения 1 и 2, а в области 2 есть растения 2 и 3, таблица areas_plants
будет выглядеть так:
area_id | plant_id | sort_idx
-----------------------------
1 | 1 | 0
1 | 2 | 1
2 | 2 | 0
2 | 3 | 1
Затем вы можете искать отношения с обеих сторон и использовать простые JOIN для получения соответствующих данных из любой таблицы. Не нужно гадать в условиях LIKE, чтобы выяснить, входит ли это в список, blah, bleh, yuck. Я был там для устаревшей базы данных. Не весело. Используйте SQL с наибольшим потенциалом.
Ответ 2
Как насчет этого:
таблица: растения
plant_ID | name
1 | tree
2 | shrubbery
20 | notashrubbery
таблица: области
area_ID | name
1 | forest
table: area_plant_map
area_ID | plant_ID | sequence
1 | 1 | 0
1 | 2 | 1
1 | 20 | 2
Это стандартный нормализованный способ сделать это (с таблицей сопоставления).
Чтобы найти все области с кустарником (растение 2), сделайте следующее:
SELECT *
FROM areas
INNER JOIN area_plant_map ON areas.area_ID = area_plant_map.area_ID
WHERE plant_ID = 2
Ответ 3
Вы знаете, что это нарушает нормальную форму?
Как правило, у каждой таблицы были бы таблицы isaplants: area_ID, plant_ID с уникальным ограничением на два и внешние ключи для двух других таблиц. Эта таблица "ссылок" - это то, что дает вам много-много или многих-к-одному.
Запросы на это, как правило, очень эффективны, они используют индексы и не требуют разбора строк.
Ответ 4
Ваши атрибуты отношения должны быть атомарными, но не состоящими из нескольких значений, таких как списки. Слишком сложно их искать. Вам нужно новое отношение, которое сопоставляет растения с идентификатором area_ID, и комбинация area_ID/plant является основным ключом.
Ответ 5
Использовать отношения "многие-ко-многим":
CREATE TABLE plant (
plant_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255)
) ENGINE=INNODB;
CREATE TABLE area (
area_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255)
) ENGINE=INNODB;
CREATE TABLE plant_area_xref (
plant_id INT NOT NULL,
area_id INT NOT NULL,
sort_idx INT NOT NULL,
FOREIGN KEY (plant_id) REFERENCES plant(plant_id) ON DELETE CASCADE,
FOREIGN KEY (area_id) REFERENCES area(area_id) ON DELETE CASCADE,
PRIMARY KEY (plant_id, area_id, sort_idx)
) ENGINE=INNODB;
EDIT:
Чтобы ответить на ваш вопрос о бонусе:
Bonus Question Is it time to step away from MySQL? Is there a better DB to manage this?
Это не имеет ничего общего с MySQL. Это была просто проблема с плохим дизайном базы данных. Вы должны использовать таблицы пересечений и отношения "многие ко многим" для таких случаев в каждой СУБД (MySQL, Oracle, MSSQL, PostgreSQL и т.д.).