Leave a Comment
Mysql: поиск по полю с выставленным битом (по битовой маске)
Допустим есть таблица, где есть много записей. И нужно поработать с фильтрами по битовому полю.
Вот таблица:
1 2 3 4 5 |
CREATE TABLE IF NOT EXISTS `tt` ( `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, `type` bigint(20) unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_general_ci; |
Выставляется бит так:
1 |
UPDATE tt SET type = type & 60 WHERE id = 1 |
Убирается так:
1 |
UPDATE tt SET type = type & ~60 WHERE id = 1 |
Так вот.
Нужно сделать выборку только тех записей, у кого выставлен бит.
-
В лоб. Не используется индекс по type.
123456789EXPLAIN EXTENDEDSELECT*FROM `Monamour2`.`Anketa` AS ttWHERE tt.type & 1 << 60LIMIT 15;-- id select_type table type possible_keys key key_len ref rows filtered Extra-- ------ ----------- ------ ------ ------------- ------ ------- ------ ------- -------- ------------- 1 SIMPLE tt ALL (NULL) (NULL) (NULL) (NULL) 4926268 100.00 Using where -
Магия. Используется индекс по type
12345678910EXPLAIN EXTENDEDSELECT*FROM `Monamour2`.`Anketa` AS ttWHERE tt.type & 1 << 60AND tt.type >= 0xFFFFFFFF & ~((2 << FLOOR(LOG(2, 0xFFFFFFFF & ~(1 << 60)))) - 1)LIMIT 15;-- id select_type table type possible_keys key key_len ref rows filtered Extra-- ------ ----------- ------ ------ ------------- ------ ------- ------ ------- -------- ------------- 1 SIMPLE tt range type type 8 (NULL) 2463134 100.00 Using where
Но всё равно просмотрено много строк из таблицы. Значительно лучше так: -
Используется ещё и covering index
12345678910111213141516171819EXPLAIN EXTENDEDSELECTtt.*FROM ttINNER JOIN(SELECTtt.oidFROM ttWHERE tt.type & 1 << 62AND tt.type >= 0xFFFFFFFF & ~((2 << FLOOR(LOG(2, 0xFFFFFFFF & ~(1 << 60)))) - 1) LIMIT 15) AS tt2USING(oid);-- id select_type table type possible_keys key key_len ref rows filtered Extra-- ------ ----------- ---------- ------ ------------- ------- ------- ------ ------- -------- -------------------------- 1 PRIMARY <derived2> ALL (NULL) (NULL) (NULL) (NULL) 6 100.00-- 1 PRIMARY aa eq_ref PRIMARY PRIMARY 4 a.oid 1 100.00-- 2 DERIVED a range type type 8 (NULL) 2463134 100.00 Using where; Using index
Здесь самый «тяжёлый» запрос использует covering index.
Что можно почитать по теме:
http://stackoverflow.com/questions/1457218/bitwise-supersets-and-subsets-in-mysql
http://dev.mysql.com/doc/refman/5.0/en/bit-functions.html
Similar Posts
LEAVE A COMMENT
Для отправки комментария вам необходимо авторизоваться.