2017-02-02 7 views
-1

FCM маркер в форматеFirebase лексема структура и хранение

fKk623mCfkm4:APA21bG2PqYzjxkwVElcODnMdTk9BP1AoNw- 
rogg8uUdK9lzIc0Ow0KVa_19PRZE85v_0VZjBPBve4PAwqX9mVstr 
o2fnzWoChgOVdIRU0YvOMRniOwg-KGB5EjajqD3Szl2lBwPZQBJ 

Который довольно долго.

Если вы хотите сохранить токен в MySQL и убедиться, что токен уникален, как бы это сделать? Я считаю, что строка слишком длинная для индексации. Можно ли предположить, что часть до двоеточия (в данном случае fKk623mCfkm4) уникальна в рамках приложения? Если это так, это будет гораздо более разумным способом индексирования токена. (Только VARCHAR по-прежнему, но с CREATE UNIQUE INDEX fcm_token ON myTable myColumn(12))

Я понимаю, что это может быть длинным выстрелом, так: Как решить эту проблему?

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

Строка из 12 буквенно-цифровых символов может выдавать 5.906682292E37 различные результаты. Такая случайность кажется, что этого было бы достаточно, чтобы избежать столкновения в рамках одного приложения. Редактировать: Плохая идея.

Я делаю это в настоящее время:

CREATE TABLE `devices` (
`ID` int(10) unsigned NOT NULL AUTO_INCREMENT, 
`USER` int(10) unsigned NOT NULL, 
`TOKEN` varchar(255) NOT NULL, 
`TOKENSHA1` binary(20) DEFAULT NULL, 
`MODIFIED` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 
PRIMARY KEY (`ID`), 
UNIQUE KEY `TOKENSHA1` (`TOKENSHA1`), 
KEY `USER` (`USER`), 
KEY `MODIFIED` (`MODIFIED`) 
) ENGINE=InnoDB 
+0

Это сводится к тому, что деталь перед двоеточием уникальна или нет. Если это не так, вам нужно проиндексировать весь контент. – Shadow

+0

Да, но я не могу найти никакой информации об этом где угодно. Надеюсь, кто-то из FCM это узнает. – nickdnk

+0

Тогда это то, что вы должны спросить. – Shadow

ответ

1

Этот пример строки не слишком долго, чтобы индекс в двигателе InnoDB в MySQL.

Двигатель innodb MySQL имеет максимальную длину ключа ключа 767 байт.

MySql Reference

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

  1. Просто проиндексируйте всю строку (выглядит как 156 символов).
  2. индексировать SHA1 хэш строки (40 шестнадцатеричных цифр) от sha1 MySQL() функции
  3. Индекса двоичного SHA1 (20 байт)
  4. Если база 64 кодируется с использованием документированного кодирования, вернуть его двоичная форма и индекс.

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

Документация Firebase, которую я прочитал, представляет этот токен как просто токен, без объяснения его содержания. Он выглядит в кодировке base64, но я не видел, чтобы это было документировано.

+0

Я знаю, что это не слишком * долго, но с точки зрения производительности я понял, что это может быть не очень хорошая идея. Возможно, я переусердствовал. Думаю, я нашел способ избежать уникального индекса. Ваши предложения с хешированием хороши! Я рассмотрю :) – nickdnk

1

Примечание для других читателей: В этом ответе предполагается, что единственной целью таблицы является захват дубликатов. Это предположение оказывается неправильным.

Насколько велик ваш стол? Допустим, у вас 1 миллион строк. Этот индекс (собственный собственный BTree) займет около 250 МБ на диске. Сколько у вас RAM? Что такое настройка innodb_buffer_pool_size? Они, вероятно, достаточно большие, чтобы приложить некоторые усилия для кэширования 250 МБ. Если вам не нужно тестировать более 100 токенов в секунду, даже если вам нужно ударить диск, это не должно быть проблемой. 100 вставок/сек будут добавлять до 8M строк в день.

Похоже, маркер ASCII, так что не забудьте указать кодировку, что-то вроде

FCM VARCHAR(156) CHARACTER SET ascii NOT NULL 

Не делать CREATE UNIQUE INDEX ... myColumn(12) - что будет хранить целые 156 символов, но проверить только 12 уникальности. Это практически бесполезная функция, и часто это «неправильная» вещь.

планы A, B, C

Если единственная цель состоит в том, чтобы проверить, является ли уже видно строка 156-символ ...

План A:

CREATE TABLE x (
    fcm CHAR(156) CHARACTER SET ascii NOT NULL, 
    PRIMARY KEY(fcm) 
    ) ENGINE=InnoDB; 

0 копий идентификатора (0 байт)
0 копия SHA1 (0)
1 экземпляр TOKEN (156 байт, при условии, ASCII)

Итого: 156 байт (плюс накладные расходы)

План B:

CREATE TABLE x (
    digest BINARY(16) NOT NULL, -- MD5(fcm) 
    PRIMARY KEY(digest) 
    ) ENGINE=InnoDB; 

0 копии ID (0 байт)
1 копия MD5 (16 байт)
0 копии лексем (0 байт)

Итого: 16 байт

Любая из этих планов ч as BTree. Либо очень быстро проверит один дубликат. Либо будет касаться только одного блока, когда вы выберете новую строку.

План A займет больше места, чем Plan B. Некоторые из них обеспокоены случайными дублировками в дайджесте (MD5, SHA1 и т. Д.) И будут избегать плана B, иначе я бы не включил Plan A вообще.

Любой план в конечном счете замедляется - это произойдет, когда таблица станет настолько большой, что ее невозможно кэшировать в ОЗУ. Когда таблица в 20 раз больше, чем кеш, только 1/20 поисковых запросов найдут запись в ОЗУ. План A, будучи больше, начнет замедляться раньше.

План C: Ввод и 156 и 16 в таблице делают для большего стола. Следовательно, вы быстрее достигаете замедления (по крайней мере, одного из A или B), независимо от того, как он индексируется.

PRIMARY KEY(md5) 

0 копии ID (0 байт)
1 экземпляр md5 (16 байт)
1 экземпляр лексем (156 байт, предполагая ASCII)

Итого: 172 байт

После добавления более столбцов и индексов

План D (по nickdnk):

PRIMARY KEY (`ID`), 
UNIQUE KEY `TOKENSHA1` (`TOKENSHA1`), 
KEY `USER` (`USER`), 
KEY `MODIFIED` (`MODIFIED`) 

4 копии ID (4 * 4 байта)
2 копии SHA1 (2 * 20 байтов, предполагая Binary (20), а не VARCHAR)
1 экземпляр лексем (156 байт, предполагая ASCII)

Итого: 212 байтов (плюс накладные)

План Е:

PRIMARY KEY(TOKEN), 
INDEX(USER), 
INDEX(MODIFIED) 

0 копии ID (0 байт)
0 копии SHA1 (0 байт)
3 копии лексем (3 * 156 байт, предполагая ASCII)

Итого: 468 байт

Plan F:

PRIMARY KEY(TOKENSHA1), 
INDEX(USER), 
INDEX(MODIFIED) 

0 копии ID (0 байт)
3 копия SHA1 (3 * 20 байт)
1 экземпляр лексем (156 байт, предполагая ASCII)

Итого: 216 байтов

Итак, ваш план (D) хорош, особенно если вам нужно больше индексов. Мой план F по существу хорош. (Потери на 4 байта компенсируются служебными данными.)

INSERTs замедлились, некоторые из них должны были проверить два ключа UNIQUE. SELECTsмай столкновение разница в характеристиках.

+0

Я закончил работу с хэшем SHA1 маркера, а затем проиндексировал его в двоичном (20) поле, используя UNHEX. Я думаю, что это решение дает мне то, что я хочу: автоинкрементный первичный ключ и компактный уникальный индекс для идентификации токенов, сохраняя при этом фактические токены в полной памяти (varchar 255, * without * index). – nickdnk

+0

Я предлагаю, чтобы SHA1 не стоил лишних хлопот. Столбец InnoDB с 1 столбцом с 156-символьным «PRIMARY KEY» является _smaller_, чем этот _plus_ столбцом и индексом в 20-байтовом шаге1. –

+0

Но первичный ключ случайных данных не является большой идеей в долгосрочной перспективе, как я понимаю. Например, здесь: http://kccoder.com/mysql/uuid-vs-int-insert-performance/ - и это только с uuid, который составляет всего 16 символов, а не 156 символов. Идея состоит в том, чтобы поддерживать скорость и предотвращать фрагментацию с помощью вторичного индекса AI PK +. – nickdnk