Каков наиболее эффективный способ хранения массива целых чисел в столбце 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 и т.д.).