Каков наиболее эффективный способ хранения массива целых чисел в столбце MySQL? - PullRequest
13 голосов
/ 16 июля 2010

У меня есть две таблицы

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 (площадка с ведущими нулями?) Каким будет запрос для этого?

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

Бонусный вопрос Пора отойти от MySQL?Есть ли лучшая БД для управления этим?

Ответы [ 6 ]

26 голосов
/ 16 июля 2010

Если вы собираетесь искать как по лесу, так и по растению, звучит так, как будто бы вы выиграли от полноценного отношения «многие ко многим».Забросьте столбец 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

Затем вы можете искать отношения с любой стороны и использовать простые СОЕДИНЕНИЯ для получения соответствующих данных из любой таблицы.Нет необходимости разбираться в НРАВИТСЯ условиях, чтобы выяснить, если это в списке, бла, бле, чёрт.Я был там для устаревшей базы данных.Не весело.Используйте SQL с наибольшим потенциалом.

7 голосов
/ 16 июля 2010

Как насчет этого:

таблица: растения

plant_ID | name
1        | tree
2        | shrubbery
20       | notashrubbery

таблица: области

area_ID | name
1       | forest

таблица: 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 голосов
/ 16 июля 2010

Вы знаете, что это нарушает нормальную форму?

Как правило, можно иметь таблицу areaplants: area_ID, plant_ID с уникальным ограничением на два и внешние ключи для двух других таблиц.Эта таблица «связей» - это то, что дает вам отношения «многие-многие» или «многие-к-одному».

Запросы по этому вопросу, как правило, очень эффективны, они используют индексы и не требуют разбора строк.

2 голосов
/ 26 июня 2018

8 лет после того, как этот вопрос был задан, вот 2 идеи:

1. Используйте тип json (ссылка)

Начиная с MySQL 5.7.8, MySQL поддерживает собственный тип данных JSON, определенный в RFC 7159, который обеспечивает эффективный доступ к данным в документах JSON (JavaScript Object Notation).

2. Используйте свою собственную кодификацию

Превратите area_id в строковое поле (varchar или текст, ваш выбор, подумайте о производительности), затем вы можете представить значения, как, например, -21-30-2-4-20-, затем вы можете фильтровать, используя %-2-%.

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

-

Помните, что при использовании любого из этих нарушений первое правило нормализации гласит: every column should hold a single value

2 голосов
/ 16 июля 2010

Используйте отношение «многие ко многим»:

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;

РЕДАКТИРОВАТЬ:

Просто чтобы ответить на ваш бонусный вопрос:

Bonus Question Is it time to step away from MySQL? Is there a better DB to manage this?

Это не имеет ничего общего сMySQL.Это была просто проблема с плохим дизайном базы данных.Вы должны использовать таблицы пересечений и отношения «многие ко многим» для подобных случаев в каждой СУБД (MySQL, Oracle, MSSQL, PostgreSQL и т. Д.).

2 голосов
/ 16 июля 2010

Ваши атрибуты отношения должны быть атомарными, а не состоять из нескольких значений, таких как списки. Слишком сложно их искать. Вам нужно новое отношение, которое отображает растения в area_ID, а комбинация area_ID / plant является первичным ключом.

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