SQLinfo.ru - Все о MySQL

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

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

Вы не зашли.

#1 02.10.2007 23:55:39

Shad
Завсегдатай
Зарегистрирован: 02.10.2007
Сообщений: 25

Как оптимальнее работать с флагами?

Собственно вопрос в оптимизации хранения флагов и выборок по ним.
1). Лучше хранить их побитово и делать выборки с помощью побитовой маски?
where (bitsflag&3)=3
2). Или быстрее будут выборки, когда флаги будут храниться в отдельных полях.
where flag1='yes' and flag2='yes'

Интересует выигрыш именно в скорости.
Флагов где-то десяток-два.
Таблицы большие, где-то с десяток миллионов записей.

Отредактированно Shad (02.10.2007 23:56:20)

Неактивен

 

#2 03.10.2007 00:03:43

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

Re: Как оптимальнее работать с флагами?

1. Запросы вида "(вычисляемое выражение) = значение" никогда не будут использовать
индекс, поэтому они плохи сами по себе.

2. Хранить флаги строками - не нужно, индексы по строкам будут работать отвратительно
медленно (по сравнению с числами).

3. Хранить флаги отдельно побитово (столбцы типа BIT) - это замечательно с точки зрения
места, но индекс имеет смысл натягивать только на очень большое количество таких
столбцов, т.к. у бинарного поля будет очень маленькая cardinality на 10кк строк smile

--

Я бы остановился или на варианте
where flags = 3
(почти Ваш первый вариант, но использует индекс), или на
flag1=1 and flag2=1
(с индексом на flag1, flag2)

Минусы, впрочем, тоже очевидны, т.к. индекс будет использоваться только при правильном
указании последовательности флагов.

Отредактированно paulus (03.10.2007 00:06:53)

Неактивен

 

#3 03.10.2007 01:08:24

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3878

Re: Как оптимальнее работать с флагами?

Как вариант можно создать несколько составных ключей для разных наборов атрибутов. Такое можно себе позволить, только если INSERTы редки.

Неактивен

 

#4 03.10.2007 01:27:28

Shad
Завсегдатай
Зарегистрирован: 02.10.2007
Сообщений: 25

Re: Как оптимальнее работать с флагами?

Спасибо за ответ.
Я во втором своем варианте предполагал, что будут использоваться не строки, а enum. Или с этим типом индекс тоже не используется?
Можно еще немного пообсуждать предложенные вами варианты?

1. Вариант с простым сравнением "flags=3".
Подразумевается, что флаги мы храним так же, как и раньше, побитово? А если нужно сделать выборку по одному из установленным флагов, то будем писать что-то вроде:
flags=1 or flags=3 or flags=5 or flags=9 or flags=17 or flags=33 or ... и так столько раз, сколько у нас флаговых бит (ну или через "IN(1,3,5,9,17,33,...)")
А если надо сделать более сложные выборки (с десятками флагов в разных состояниях)? Что-то мне уже как-то становится не по себе. smile

2. Вариант "flag1=1 and flag2=1" собственно понятен.
Вопрос только "по правильному указанию последовательности флагов". Что вы имели в виду, можно чуть подробнее.

Неактивен

 

#5 03.10.2007 01:36:17

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

Re: Как оптимальнее работать с флагами?

1. IN может оказаться достаточно большим smile
Для Вашего десятка битов с двумя фиксированными это 2^8 = 256 комбинаций.

Хотя, с другой стороны, это не так уж и много. Или я считаю не правильно?

2. Последовательно - это принцип работы индексов. Пусть у Вас есть индекс,
натянутый на поля (f1, f2, f3). Тогда он будет использоваться так:

запрос "f1=1 and f2=1 and f3=1" - отлично, весь индекс используется
запрос "f1=1 and f2=1 and f4=1" - используется только часть индекса (f1,f2)
запрос "f2=1 and f3=1 and f4=1" - индекс не используется, потому что нет f1.

Используется только самая левая часть полей в индексе.

--

Вообще, случай с IN для десяти битов мне представляется сейчас оптимальным.
Для 20 битов вы не сможете выписать IN за разумное время smile

Неактивен

 

#6 03.10.2007 01:47:27

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

Re: Как оптимальнее работать с флагами?

Обсуждения с rgbeast навели на мысль, что надо бить флаги на кусочки по несколько бит
и писать через IN. Т.е. как-то так:

1. Есть 20 бит информации. Мы ее бьем на три байта по 8 бит: f1, f2, f3.
2. Натягиваем индексы на (f1, f2, f3), (f1, f3), (f2, f3), (f3).
3. Ищем с помощью f1 IN (...) and f2 IN (...) and f3 IN (...), произвольно опуская куски,
если они не нужны.

Неактивен

 

#7 03.10.2007 01:47:32

Shad
Завсегдатай
Зарегистрирован: 02.10.2007
Сообщений: 25

Re: Как оптимальнее работать с флагами?

paulus написал:

запрос "f1=1 and f2=1 and f4=1" - используется только часть индекса (f1,f2)

Это даже если есть отдельный индекс для f4? Он не поможет в таком запросе?
(Updated: исходя из вашего предыдущего поста, сделал вывод, что не поможет). sad

paulus написал:

Вообще, случай с IN для десяти битов мне представляется сейчас оптимальным.
Для 20 битов вы не сможете выписать IN за разумное время smile

Вот. smile Этого я и боюсь. Живые проекты имеют свойство усложнятся.
(Updated: хотя идея с разбиением на несколько составных битовых полей греет мне душу).  smile

Отредактированно Shad (03.10.2007 01:51:29)

Неактивен

 

#8 03.10.2007 01:53:31

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

Re: Как оптимальнее работать с флагами?

А Вы уверены, что нужно хранить именно битовую информацию и по ней искать?
Наверняка, есть какие-то более разумные (и более селективные) критерии поиска,
чем наличие нескольких бит информации.

Неактивен

 

#9 03.10.2007 02:01:49

Shad
Завсегдатай
Зарегистрирован: 02.10.2007
Сообщений: 25

Re: Как оптимальнее работать с флагами?

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

Неактивен

 

#10 03.10.2007 02:11:29

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3878

Re: Как оптимальнее работать с флагами?

В обсуждении с paulus, возникла мысль, что если аттрибутов много всего, а для каждой записи их мало, то есть много нулей и мало единичек (аналог разреженной матрицы), то можно использовать другой алгоритм.

Каждому атрибуту приписать слово, а атрибуты все вместе хранить в строковом поле через пробел. Например 'strong green wide active" или "inuse white flexible active". Поиск строк с необходимыми атрибутами можно проводить, используя FULLTEXT индекс (аналог того, что используют поисковые системы). При этом нужно учитывать, что если стрибут присущ более половине строк, то FULLTEXT-поиск не будет учитывать такие атрибуты при выборке (будет считать их общеупотребимыми stop-словами). Поведение по умолчанию можно отключить, перекомпилировав MySQL

Неактивен

 

#11 03.10.2007 02:14:34

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

Re: Как оптимальнее работать с флагами?

Ну, может, там помимо флагов есть еще поле "цвет глаз", которое является решающим smile
А не просто флаги "наличие головы", "наличие усов".

Я имею в виду, что можно применять не только знание о том, что есть поля, но и знание
о том, что в них содержится. Зачастую очень упрощает запросы и способы хранения
информации smile

А вообще задачка прикольная smile

Неактивен

 

#12 03.10.2007 02:15:05

Shad
Завсегдатай
Зарегистрирован: 02.10.2007
Сообщений: 25

Re: Как оптимальнее работать с флагами?

Да нет, атрибуты равномерненько так перемешаны. smile Никаких разреженных матриц.

Неактивен

 

#13 03.10.2007 07:05:51

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

Re: Как оптимальнее работать с флагами?

Я вот тут еще что подумал... Вам насколько нужно это быстро отдавать? Если это
какой-то внутренний статистический запрос (т.е. время ~секунды приемлемо), то
можно сделать хитрое читерство:

CREATE TABLE flagger (id INT NOT NULL, flags INT NOT NULL) ENGINE=InnoDB;
CREATE TABLE data (id INT NOT NULL KEY AUTO_INCREMENT, ...);

Таблица flagger _без_ индексов вообще, 10кк строк * 8 байт на строку = 80 мегабайт.
InnoDB, чтобы влезло целиком в buffer_pool и работало из памяти smile
Запросы организовывать так:

SELECT ... FROM data WHERE id IN (SELECT id FROM flagger WHERE flags & mask = mask);

Есть подозрение, что Вам наверняка нужны не все флаги с маской, а только первые
50, скажем. Это LIMIT. LIMIT вы внутрь такого селекта не подпишете, но подпишете его
сбоку:
SELECT STRAIGHT JOIN ... FROM flagger f JOIN data d USING(id) WHERE flags & mask = mask LIMIT 50;

Или, если хочется, чтобы летало сразу (а не после загрузки в innodb buffer pool),
то положить данные в MEMORY-табличку smile или в MyISAM-табличку в tmpfs.

Неактивен

 

#14 03.10.2007 16:35:50

Shad
Завсегдатай
Зарегистрирован: 02.10.2007
Сообщений: 25

Re: Как оптимальнее работать с флагами?

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

Отредактированно Shad (03.10.2007 16:37:07)

Неактивен

 

#15 03.10.2007 19:42:02

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

Re: Как оптимальнее работать с флагами?

Да. Скорость будет не очень большая, но вполне приемлемая.

LIMIT спасает всегда. Это очень хороший стимул оптимизатору использовать индексы.

Неактивен

 

#16 03.10.2007 21:04:57

Shad
Завсегдатай
Зарегистрирован: 02.10.2007
Сообщений: 25

Re: Как оптимальнее работать с флагами?

Я в том смысле, что для моей задачи нужно ставить не LIMIT 50, а LIMIT 200000.
И он не всегда даст преимущество - чаще количество найденных записей будет меньше лимита.

Неактивен

 

#17 03.10.2007 21:09:19

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

Re: Как оптимальнее работать с флагами?

Интересно, что же Вы такое храните там smile

Неактивен

 

#18 03.10.2007 21:23:19

Shad
Завсегдатай
Зарегистрирован: 02.10.2007
Сообщений: 25

Re: Как оптимальнее работать с флагами?

Записи, которые нужно искать по флагам. smile

Неактивен

 

#19 05.06.2008 11:21:50

hrumcraft
Участник
Зарегистрирован: 05.06.2008
Сообщений: 1

Re: Как оптимальнее работать с флагами?

А если хранить информацию о флагах во внешней таблице?
Типа "Многие-ко-многим!
Индекс хорошим будет и не будет избыточности если флаги не оптимальны...

Неактивен

 

#20 05.06.2008 11:25:46

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3878

Re: Как оптимальнее работать с флагами?

Если флаг булевый, то CARDINALITY индекса не будет большим в любом случае

Неактивен

 

Board footer

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