Возможно, решение очевидно, но я не могу найти хороший.Сохранение элемента, помеченного многими категориями - битмаскировка?
В моем предстоящем проекте будет одна основная таблица, ее данные будут часто читаться. Скорость обновления/вставки/удаления не является проблемой.
Элементы этой основной таблицы связаны с 4 или более категориями. У товара может быть 50 - 100 или более отношений в пределах одной категории.
Наиболее распространенные операции, которые будут выполнены на базе:
- выбрать все элементы, которые были назначены на категории A, B, C, ... с LIMIT X, Y
- подсчета всех элементы, которые были assignged к категории A, B, C, ...
Моя первая мысль о том, как создать базу данных для вышеперечисленного было что-то вроде этого (классический подход, я думаю):
Во-первых, для каждой из четырех категорий, я создаю category
таблицу:
id - PK, int(11), index
name - varchar(100)
тогда у меня будет один item
стол:
id - PK, int(11), index
... some more data fields, about 30 or so ...
и соотносить the category
таблицы, будет 4 или больше таблиц поиска/ММ:
id_item - int(11)
id_category - int(11)
Запросов выглядели примерно так:
select
item.*
from
item
inner mm_1 on mm_1.id_item = item.id
inner join cat_1 on cat_1.id = mm_1.id_category and cat_1.id in (1, 2, ... , 100)
inner mm_2 on mm_2.id_item = item.id
inner join cat_2 on cat_2.id = mm_2.id_category and cat_2.id in (50, 51, ... , 90)
Конечно вышеописанный подход с таблицами ММ будет работать, но, как приложение должно обеспечить очень хорошую SELECT
производительности, я тестировал с реальными объемами данных (100000 записей в таблица item
, 50 - 80 отношений в каждой категории), но это было не так быстро, как я ожидал, даже с индексами на месте. Я также пытался использовать WHERE EXISTS
вместо INNER JOIN
при выборе.
Моя вторая идея состояла в том, чтобы просто использовать item
таблицу сверху денормализовать данные.
После прочтения this blog post об использовании битмаски я дал ему попробовать и присваивается каждой категории значение бита:
category 1.1 - 1
category 1.2 - 2
category 1.3 - 4
category 1.4 - 8
... etc ...
Таким образом, если item
был помечен category 1.1
и category 1.3
, он имел битовую маску 5
, который то я хранится в поле item.bitmask
и я могу запросить его следующим образом:
select count(*) from item where item.bitmask & 5 = 5
Но производительность была не столь велика либо.
Проблемы с этим bitmasking подход: MySQL не использует никаких индексов, когда битовые операторы участвуют и даже тогда, когда item.bitmask
будет иметь тип BIGINT
я могу только обрабатывать до 64 отношений, но мне нужно поддерживать до 100 в категория.
Это было о нем. Я не могу думать ни о чем другом, кроме, может быть, загрязнять таблицу item
со многими, многими полями, такими как category_1_1
до category_4_100
. Каждый из них содержит либо 1, либо 0. Но это может привести к многим AND
в предложении выбора, и это не кажется как хорошая идея.
Итак, какие у меня варианты? Какие-нибудь лучшие идеи?
EDIT: как ответ на Cory Petosky комментарий «Что„Элемент может иметь 50 - 100 или более отношений в рамках одной категории“означают?»:
Чтобы сделать его более конкретным. , таблица item
представляет изображение. Изображения относятся к числу других критериев, классифицированных по настроениям (настроение будет одной из 4 категорий). Так это будет выглядеть следующим образом:
Image:
- Category "mood":
- bright
- happy
- funny
- ... 50 or so more ...
- Category "XYZ":
- ... 70 or so more ...
Если мой стол изображение будет класс в C#, она будет выглядеть следующим образом:
public class Image {
public List<Mood> Moods; // can contain 0 - 100 items
public List<Some> SomeCategory; // can contain 0 - 100 items
// ...
}
Что такое «У предмета может быть 50 - 100 или более отношений внутри одной категории». имею в виду? Я не понимаю все разные категории, которые вы создаете/ссылаетесь. –