Как избежать вторичных индексов в кассандре?

Я неоднократно слышал, что вторичные индексы (в кассандре) предназначены только для удобства, но не для лучшей производительности. Единственный случай, когда рекомендуется использовать вторичные индексы при низкой мощности (например, пол column, который имеет два значения: мужской или женский)

рассмотрим этот пример:

CREATE TABLE users ( 
userID uuid, 
firstname text, 
lastname text, 
state text, 
zip int, 
PRIMARY KEY (userID) 
);

прямо сейчас я не могу выполнить этот запрос, если не создаю вторичный индекс на users на firstname index

select * from users where firstname='john'

Как мне денормализовать эту таблицу, чтобы я мог получить этот запрос: Это единственный эффективный способ с помощью составных клавиш? Любые другие варианты или предложения?

CREATE TABLE users ( 
    userID uuid, 
    firstname text, 
    lastname text, 
    state text, 
    zip int, 
    PRIMARY KEY (firstname,userID) 
    );

Ответ 1

Чтобы создать хорошую модель данных, вам нужно определить первые ВСЕ запросы, которые вы хотите выполнить. Если вам нужно только искать пользователей по их первому имени (или первому и идентификатору пользователя), тогда ваш второй дизайн будет...

Если вам также нужно искать пользователей по их фамилии, вы можете создать другую таблицу с теми же полями, кроме первичного ключа (lastname, userID). Очевидно, вам нужно будет обновить обе таблицы в одно и то же время. Дублирование данных в Кассандре прекрасное.

Тем не менее, если вас беспокоит пространство, необходимое для двух или более таблиц, вы можете создать единую таблицу пользователей, разделенную идентификатором пользователя, и дополнительные таблицы для полей, которые вы хотите запросить:

CREATE TABLE users ( 
    userID uuid, 
    firstname text, 
    lastname text, 
    state text, 
    zip int, 
    PRIMARY KEY (userID) 
);

CREATE TABLE users_by_firstname (
    firstname text,
    userid uuid,
    PRIMARY KEY (firstname, userid)
);

Недостатком этого решения является то, что вам потребуются два запроса для извлечения пользователей по их имени:

SELECT userid FROM users_by_firstname WHERE firstname = 'Joe';
SELECT * FROM users WHERE userid IN (...);

Надеюсь, что это поможет

Ответ 2

Есть несколько способов сделать это, все с плюсами и минусами.

  • Второй запрос будет работать, но это только таблица индексов. http://wiki.apache.org/cassandra/SecondaryIndexes Дополнительный индекс может быть полезен, и если вы сначала нажмете раздел (который вы не можете сделать в своей первой таблице), то реализация cassandra избавит вас от хлопот и сохранит "локальный атом". Не попав в раздел, ваша первая таблица с индексом не будет отличной в вашем запросе, так как она повсеместно ударит по всему.

  • Вы можете полностью денормализовать, но вы также можете просмотреть таблицу. т.е. ваша вторая таблица может существовать только для возврата идентификатора пользователя. Затем вы можете выполнить второй запрос для извлечения информации только для соответствующих разделов. Если вы ожидаете нескольких результатов, это может быть хорошо. Если нет, вы столкнетесь с множеством разделов на многих узлах (которые в зависимости от вашего размера кластера и критериев избегания hotspot могут быть хорошими или плохими). Выполнение многих запросов ~ 1 мс обычно лучше, чем выполнение одного запроса ~ 1000 мс.

  • Вы можете сделать искусственный bucketing и выпустить запросы n = bucketcount. У этого есть дополнительные накладные расходы, но уменьшает количество запросов и может быть хорошим вариантом.

  • Ваш индекс может иметь первые несколько символов первого имени. Или это может быть последовательный хеш в несколько ведер. Первый может дать вам семантику "начинается с".

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