Как искать запись, используя ORDER_BY без ключей раздела - PullRequest
1 голос
/ 26 июня 2019

Я отлаживаю проблему, и журналы должны находиться в промежутке времени между 4/23/19 ~ 4/25/19

На нашем производстве находятся сотни миллионов записей.Невозможно найти целевые записи, используя случайную сортировку.

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

select * from XXXX.report_summary order by updated_at desc

Схема

...
"modified_at"   "TimestampType" "regular"
"record_end_date"   "TimestampType" "regular"
"record_entity_type"    "UTF8Type"  "clustering_key"
"record_frequency"  "UTF8Type"  "regular"
"record_id" "UUIDType"  "partition_key"

1 Ответ

2 голосов
/ 26 июня 2019

Во-первых, ORDER BY действительно излишне в Кассандре. Он может работать только с вашими столбцами кластеризации в пределах раздела, и только в точном порядке столбцов кластеризации. Причина этого в том, что Cassandra последовательно читает с диска, поэтому для начала записывает все данные в соответствии с заданным порядком кластеризации.

Так что IMO, ORDER BY в Кассандре довольно бесполезен, за исключением случаев, когда вы хотите изменить направление сортировки (по возрастанию / по убыванию).

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

Таким образом, рекомендуемый способ сделать это - создать такую ​​таблицу:

CREATE TABLE stackoverflow.report_summary_by_month (
    record_id uuid,
    record_entity_type text,
    modified_at timestamp,
    month_bucket bigint,
    record_end_date timestamp,
    record_frequency text,
    PRIMARY KEY (month_bucket, modified_at, record_id)
) WITH CLUSTERING ORDER BY (modified_at DESC, record_id ASC);

Тогда этот запрос будет работать:

SELECT * FROM report_summary_by_month
WHERE month_bucket = 201904 
AND modified_at >= '2019-04-23' AND modified_at < '2019-04-26';

Идея здесь заключается в том, что, поскольку вы заботитесь о порядке результатов, вам нужно разделить что-то еще, чтобы обеспечить возможность сортировки. Для этого примера я выбрал месяц, поэтому я «разбил» ваши результаты по месяцам на ключ раздела под названием month_bucket. В течение каждого месяца я группирую по окончанию порядка modified_at в DESC. Таким образом, самые последние результаты находятся в верхней части раздела. Затем я добавил record_id в качестве ключа тай-брейка, чтобы обеспечить уникальность.

Если вы все еще сосредоточены на том, чтобы делать это неправильно:

Вы можете фактически выполнить запрос диапазона в вашей текущей схеме. Но с «сотнями миллионов записей» на нескольких узлах у меня нет больших надежд на то, что это сработает. Но вы можете сделать это с помощью директивы ALLOW FILTERING (которую вы никогда не должны использовать).

SELECT * FROM report_summary
WHERE modified_at >= '2019-04-23'
AND modified_at < '2019-04-26' ALLOW FILTERING;

Этот подход имеет следующие оговорки:

  • При большом количестве записей на многих узлах время ожидания может истечь.
  • Не имея возможности идентифицировать один раздел для этого запроса, будет выбран узел-координатор, и этот узел с большой вероятностью будет перегружен.
  • Поскольку это извлечение строк из нескольких разделов, порядок сортировки не может быть принудительно установлен.
  • ALLOW FILTERING заставляет Cassandra работать так, как он на самом деле не был предназначен, поэтому я бы никогда не использовал это в производственной системе.

Если вам действительно нужно выполнить такой запрос, я рекомендую использовать инструмент агрегирования в памяти, например Spark.

Кроме того, поскольку первоначальный вопрос был о ORDER BY, я недавно написал статью, которая лучше объясняет эту тему: https://www.datastax.com/dev/blog/we-shall-have-order

...