SQLinfo.ru - Все о MySQL

Форум пользователей MySQL

Задавайте вопросы, мы ответим

Вы не зашли.

#1 04.11.2010 15:08:30

mybd
Участник
Зарегистрирован: 04.11.2010
Сообщений: 16

Как лучше хранить большое кол-во флагов?

Вопрос №1

Есть некоторая сущность, которая имеет большое кол-во параметров, которые могут принимать значения 1 и 0.
Сколько может быть таких параметров в будущем не известно (100 думаю наберется. 200 вряд ли. 500 скорей всего нет).
Будем считать что их 100-200. Но выставленными у каждой сущности оказываются около 10.
Причем наблюдается некоторая сгруппированность. Во избежании, избыточности я сделал несколько таблиц, каждая из которых хранит группу флагов.
Т.е. грубо говоря 10 таблиц по 10 столбцов TINY INT(1) в каждой (не считая ID по, которому JOIN делается).
Соответсвенно, та группа флагов, которая выставленная в 0, просто не записывается в соответвующую таблицу.
Таким образом выборку я предполагал осуществлять, делая JOIN только тех таблиц флаги в которых меня интересуют.
Но оказалось я не всё предусмотрел. И мне нужно делать выборку по такой маске, в которой меня интересуют определенные флаги, а все остальные должны быть 0.
Т.е. мне нужно делать JOIN всех таблиц.

Всё должно работать очень быстро. Т.к. будут частые запросы по различным маскам.
Вот я и думаю а может свести все флаги в одну таблицу. Но меня почему-то пугает большое кол-во столбцов для таблицы.

Или 100-200 столбцов TINY INT(1) это нормальная таблица? A 100-200 столбцов просто INT(11)? (это я спрашиваю до кучи, т.к. вижу в перспективе и необходимость в такой таблице).
---------------------------

Вопрос №2

Что если у меня будет большое кол-во запросов, типа

SELECT * FROM tableA
INNER JOIN tableB ON tableA.id = tableB.id
WHERE ( tableA.value1 > 3 AND tableA.value2 < 5 ) AND
(tableB.flag1 OR 1) AND (!tableB.flag2) AND ...

Т.е. из одной таблицы проверяется какое-то одной условие, и к этой таблице делаются JOIN другой таблицы с условиями по флагам.
Причем первая часть условия, относящая к tableA будет часто повторятся.
Как сделать чтобы результат этот кэшировался и уже из него делалась выборка по флагам.
Объеденить таблицы в одну никак нельзя, это разные сущности.
Вроде как в MySQL есть подзапросы. Кэшируется ли результат подзапроса?
Будет ли это работать быстрее чем JOIN?

Неактивен

 

#2 04.11.2010 18:07:33

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: Как лучше хранить большое кол-во флагов?

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

Подзапросы не кэшируются. Можете сделать денормализационную табличку (или даже
временную просто на цикл запросов).

Неактивен

 

#3 04.11.2010 18:16:36

mybd
Участник
Зарегистрирован: 04.11.2010
Сообщений: 16

Re: Как лучше хранить большое кол-во флагов?

paulus написал:

... но вот индекс
над битовым полем Вы не натянете.

Поясните пожалуйста. Я вкурсе, что если бы 11100101 я хранил в одном поле, то индекс по такому полю мне ничего не дал бы. Но я намерен хранить каждый бит в отдельном поле TINY INT(1). А может и BIT(1), т.к. он на поверку оказался компактнее.
И что индекс по таким полям мне ничего не даст?

paulus написал:

В случае со sparse данными имеет смысл хранить
индексы установленных полей, а не матрицу битов — получается меньше места и
большое производительность.

Тоже хотел бы услышать пояснение. не знаю что такое sparse данные. И что подразумевается под индексами. Поле PRIMERY KEY?
Покажите пожалуйста наглядно в поле какого типа и каким образом вы предлагаете мне хранить индексы.

Неактивен

 

#4 04.11.2010 21:30:18

mybd
Участник
Зарегистрирован: 04.11.2010
Сообщений: 16

Re: Как лучше хранить большое кол-во флагов?

что такое sparse (или разреженные) данные почитал. Я так понял вы предлагаете хранить это дело так


objectID  |  flagID  |  flagValue
--------------------------
  1       |  1       |  1
  1       |  2       |  1
  1       |  4       |  1
 ...      | ...      | ...
  1       |  21      |  1
  1       |  99      |  1
  2       |  2       |  1
  2       |  3       |  1
  2       |  4       |  1


Допустим 20 записей на один объект. Объектов допустим будет 100 000.
Тогда записей в таблице будет 2 000 000. А если 1 000 000 объектов - 20 000 000 записей.
И допустим нужно выбрать объекты, у которых флаг 2 и 4 может иметь любое значение (1 или 0), а все остальные флаги должны быть 0 (т.е. записи для этих флагов должны попросту отсутствовать в таблице).
При этом вся эта таблица должна JOIN'иться к другой.
И как тогда будет выглядеть запрос? С трудом представляю, что это будет производительно. Компактно, да. Но производительно ли?
Меня в первую очередь интересует максимально возможная скорость выборки. Всё остальное не важно.

Неактивен

 

#5 05.11.2010 00:14:06

mybd
Участник
Зарегистрирован: 04.11.2010
Сообщений: 16

Re: Как лучше хранить большое кол-во флагов?

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

Сейчас у меня так:

tbl_flag_group_1

ID | f1 | f2 | f3
-----------------
 1 | 1  | 0  | 1
 2 | 1  | 0  | 1
 3 | 0  | 1  | 0
 4 | 1  | 0  | 1
 5 | 0  | 0  | 1

 tbl_flag_group_2

ID | f4 | f5 | f6
-----------------
 2 | 1  | 0  | 1
 3 | 0  | 1  | 0
 5 | 1  | 0  | 1

 ...

 tbl_flag_group_n

ID | f498 | f499 | f500
-----------------
 1 |  0   |  1   |  1
 4 |  1   |  0   |  0
 5 |  1   |  1   |  1


И когда мне нужно выбрать объекты с определенными установленными флагами. Я заведомо знаю в каких таблицах хранятся значения этих флагов, а значит делаю JOIN только нужных таблиц.
Но когда мне нужно выбрать объекты, у которых мне важно, чтобы определенные флаги были сброшены. Ситуация несколько меняется. Нужно делать JOIN гараздо большего кол-ва таблиц (т.к. нули преобладают), при том, что если в группе флагов все флаги равны нулю, то такая запись в таблице попросту отсутсвует. И мне даже не понятно как проверять на 0 флаг, записи о котором нет.
Поэтому сейчас я думаю для той группы объектов, которые я выбираю по сброшенным флагам, добавить такую таблицу:

ID | tbl_flag_group_1 | tbl_flag_group_2 | ... | tbl_flag_group_n
-----------------------------------------------------------------
 1 |       1          |        0         | ... |        1
 2 |       1          |        1         | ... |        0
 3 |       1          |        1         | ... |        0
 4 |       1          |        0         | ... |        1
 5 |       1          |        1         | ... |        1


Эта таблица, кстати построена на основе предыдущех. Т.е. та группа флагов, в которой все флаги сброшены, будет отмечена в этой таблице нулем.
Конечно, эта таблица будет тоже разрежена, ибо у меня ожидается что объект будет иметь флаги в 1, 2 максимум в 3-х группах. Но зато я заменяю одним JOIN'ом этой таблицы, множество JOIN'ов таблиц с группами флагов, записи для искомых объектов в которых отсутствуют.
А ещё можно ввести флаг 0.5 (или 2) для последней таблицы, которую я изобразил. Такой флаг будет означать, что в данной группе выставлены не все флаги. А флаг 1 будет означать, что выставлены все флаги. Таким образом, тоже можно будет сократить кол-во JOIN'уемых таблиц.

А может быть это вообще всё эконочия на спичках? Я собственно потому сюда и обратился, чтобы получить советы и рекомендации о том, как лучше мне решить мою задачу.
В любом случае меня интересуют ответы и на мои вопросы в предыдущем сообщении.

Отредактированно mybd (05.11.2010 00:20:09)

Неактивен

 

#6 05.11.2010 15:17:54

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: Как лучше хранить большое кол-во флагов?

Индекс — это способ быстро достать какие-то данные. Но это никакая не
магическая сущность — это просто сортированное дерево, по которому
можно угадать, какие строки нам нужны, а какие заведомо нет.

При выборке из таблицы за один раз Вы можете использовать только один
индекс. То есть если Вы сделаете сотню индексов каждый над своим столб-
цом — реально будет использоваться только один из них.

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

Про sparse — да, Вы поняли меня правильно. Просто если у Вас 99% значе-
ний нули, то хранить их бесполезно. Кстати, в Вашем примере третий столбец —
лишний, он всегда хранит единицы smile

Касательно отсутствующих строк — почитайте про внешние объединения
(например, LEFT JOIN).

Касательно скорости в целом — не пытайтесь понять, где будет bottleneck на
этапе первичного создания базы. Сделайте базу каким-то простым способом.
Напишите базовое приложение, которое попробует работать с этой базой. Оце-
ните, хватает ли Вам производительности. В случае, если не хватит — тогда
уже оценивайте производительнось системы и ищите методы ускорения.

Неактивен

 

#7 05.11.2010 15:44:45

mybd
Участник
Зарегистрирован: 04.11.2010
Сообщений: 16

Re: Как лучше хранить большое кол-во флагов?

paulus написал:

Про sparse — да, Вы поняли меня правильно. Просто если у Вас 99% значе-
ний нули, то хранить их бесполезно. Кстати, в Вашем примере третий столбец —
лишний, он всегда хранит единицы smile

Это да я сразу понял, просто поленился убирать этот столбец smile
Но ведь, когда мне нужно делать выборки по флагам, которые равны 0, то получается, что эти нули сразу обретают смысл(значимость). Относительность, своего рода получается, понимаете? Всё зависит то выбранной системы. И было бы конечно супер если бы я смог хранить только единицы, и при этом на основе этой информации быстро делать выборки на основе отсутствующих записей.

paulus написал:

Касательно отсутствующих строк — почитайте про внешние объединения
(например, LEFT JOIN).

За эти слова, спасибо. Наводит уже на кое-какие мысли.
Был бы благодарен, если бы вы подсказали как из sparse таблицы сделать следующие выборки.


 objectID | flagID
-------------------
    1     |   1
    1     |   2
    1     |   3
    2     |   1
    3     |   2
    3     |   3
    4     |   3
    5     |   1
    5     |   4
    6     |   5
    6     |   7


1. Выбрать объекты, у которых установлены флаги 2 и 3. Т.е должны выбраться объекты 1 и 3.
2. Выбрать объекты, у которых сброшены флаги 2 и 3. Т.е. должны выбраться объекты 5 и 6.

И JOIN этого к другой таблице по полю objectID.

Отредактированно mybd (05.11.2010 15:48:46)

Неактивен

 

#8 08.11.2010 03:09:50

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: Как лучше хранить большое кол-во флагов?

SELECT t1.objectID
FROM tablename t1 JOIN tablename t2 USING(objectID)
WHERE t1.flagID = 2 AND t2.flagID = 3.

Во втором случае — Вам понадобится общая таблица объектов,
иначе ничего не выйдет smile

SELECT o.objectID
FROM objects o
LEFT JOIN tablename t1 ON o.objectID = t1.objectID AND t1.flagID = 1
LEFT JOIN tablename t2 ON o.objectID = t1.objectID AND t1.flagID = 1
WHERE t1.objectID IS NULL OR t2.objectID IS NULL;

Неактивен

 

#9 08.11.2010 12:41:37

mybd
Участник
Зарегистрирован: 04.11.2010
Сообщений: 16

Re: Как лучше хранить большое кол-во флагов?

SELECT t1.objectID
FROM tablename t1 JOIN tablename t2 USING(objectID)
WHERE t2.flagID = 2 AND t2.flagID = 3


не работает этот запрос. даже принимая во внимание опечатку в условии WHERE

Неактивен

 

#10 08.11.2010 13:44:14

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5842

Re: Как лучше хранить большое кол-во флагов?

Если принять во внимание, что в первоначальном запросе (в отличии от вашего варианта) нет опечатки, то работает wink

mysql> SELECT t1.objectID
    -> FROM ea t1 JOIN ea t2 USING(objectID)
    -> WHERE t1.flagID = 2 AND t2.flagID = 3;
+----------+
| objectID |
+----------+
|        1 |
|        3 |
+----------+
2 rows in set (0.00 sec)

Неактивен

 

#11 08.11.2010 15:18:43

mybd
Участник
Зарегистрирован: 04.11.2010
Сообщений: 16

Re: Как лучше хранить большое кол-во флагов?

видимо у нас разные исходные данные..
я так понимаю, что предполагается наличие двух таблиц.
в одной только id объектов.. а в другой id объектов и флаги, так?
у меня по крайней мере так.. и на такой запрос выдается ошибка что нет в таблице t1 поля flagID
или я что-то не понимаю? покажите какие таблицы используются в качестве исходных?

аааа, или это запрос к одной таблице? а если условий больше? то как будет выглядеть запрос?

Отредактированно mybd (08.11.2010 15:21:14)

Неактивен

 

#12 08.11.2010 15:25:24

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5842

Re: Как лучше хранить большое кол-во флагов?

Исходные данные приведены в вашем посте http://sqlinfo.ru/forum/viewtopic.php?pid=19985#p19985

Если условий n, то придется делать n раз самообъединение

Неактивен

 

Board footer

Работает на PunBB
© Copyright 2002–2008 Rickard Andersson