Дизайн таблицы Кассандры для запроса с предикатом ORDER, LIMIT и IN - PullRequest
0 голосов
/ 09 ноября 2018

У меня есть данные, которые выглядят так:

select * from test;

 department | employee | batch_number | hash
------------+----------+--------------+-------
 dep1       | Bart     |            1 | hash1
 dep1       | Bart     |            1 | hash2
 dep1       | Lisa     |            3 | hash3
 dep1       | Lisa     |            4 | hash4
 dep1       | John     |            5 | hash5
 dep1       | Lucy     |            6 | hash6
 dep1       | Bart     |            7 | hash7
 dep1       | Bart     |            7 | hash8

И я хотел бы запросить данные с помощью предложения where для batch_number, ordering для batch_number и предиката in для employee.

В реляционной базе данных это будет выглядеть как

select * from test 
  where department='dep1' 
  and employee in ('Bart','Lucy','John') 
  and batch_number >= 2 
  order by batch_number desc 
  limit 3;

 department | employee | batch_number | hash
------------+----------+--------------+-------
 dep1       | Bart     |            7 | hash7
 dep1       | Bart     |            7 | hash8
 dep1       | Lucy     |            6 | hash6

У меня возникли некоторые проблемы при моделировании таблицы для этого запроса в Кассандре. department будет моим ключом раздела, а hash должен быть частью первичного ключа. Но я борюсь с ключами кластера и / или ((SSTable присоединен) вторичными) индексами.

Поскольку я хочу заказать на batch_number Я попытался включить его в качестве ключа кластера:

CREATE TABLE keyspace.test(
    department      TEXT,
    batch_number    INT,
    hash            TEXT,
    employee        TEXT,
    PRIMARY KEY ((department), batch_number, hash)
) WITH CLUSTERING ORDER BY (batch_number DESC);
CREATE INDEX tst_emp ON keyspace.test (employee);

Но это не учитывает запросы с предикатом in в моем индексе:

select * from keyspace.test where department='dep1' and employee in ('Bart','Lucy','John');
InvalidRequest: Error from server: code=2200 [Invalid query] message="IN predicates on non-primary-key columns (employee) is not yet supported"

Поэтому я попытался добавить столбец employee в качестве ключа кластера:

CREATE TABLE keyspace.test(
    department      TEXT,
    batch_number    INT,
    hash            TEXT,
    employee        TEXT,
    PRIMARY KEY ((department), batch_number, hash, employee)
) WITH CLUSTERING ORDER BY (batch_number DESC);

Но это терпит неудачу, потому что я не могу поместить отношение не-EQ в batch_number:

select * from keyspace.test where department='dep1' and batch_number > 1 and employee in ('Bart','Lucy','John');
InvalidRequest: Error from server: code=2200 [Invalid query] message="Clustering column "employee" cannot be restricted (preceding column "batch_number" is restricted by a non-EQ relation)"

Но всякий раз, когда я ставлю employee перед batch_number, я теряю способность заказывать batch_number:

CREATE TABLE keyspace.test(
    department      TEXT,
    employee        TEXT,
    batch_number    INT,
    hash            TEXT,
    PRIMARY KEY ((department), employee, batch_number, hash)
);

select * from keyspace.test where department='dep1' and employee in ('Bart','Lucy','John') ORDER BY batch_number DESC;
InvalidRequest: Error from server: code=2200 [Invalid query] message="Order by currently only support the ordering of columns following their declared order in the PRIMARY KEY"

Так, какой дизайн таблицы учитывал бы такой запрос? Можно ли это сделать на Кассандре?

Edit:

Другие запросы, которые я хотел бы выполнить для этой таблицы:

select * from keyspace.test where department='X' and batch_number=Y 

и

delete from keyspace.test where department='X'

Ответы [ 2 ]

0 голосов
/ 12 ноября 2018

Используя материализованное представление, которое позволяет вам упорядочить ваши данные:

CREATE MATERIALIZED VIEW mv_test AS 
SELECT
   department,
   batch_number,
   employee,
   hash 
FROM
   test 
WHERE
   department IS NOT NULL 
   AND batch_number IS NOT NULL 
   AND employee IS NOT NULL 
   AND hash IS NOT NULL 
PRIMARY KEY (department, employee, batch_number, hash) 
WITH clustering 
ORDER BY
(batch_number DESC);

Я могу выполнить следующий запрос:

SELECT * FROM mv_test 
WHERE
   department = 'dep1' 
   AND employee IN 
   (
      'Bart',
      'Lisa'
   )
   AND batch_number > 3;

Результаты упорядочены в соответствии с порядком кластеризации:

 department | employee | batch_number | hash
------------+----------+--------------+-------
       dep1 |     Bart |            7 | hash7
       dep1 |     Bart |            7 | hash8
       dep1 |     Lisa |            4 | hash4

Хотя предложения > не равны, IN, хотя и имеет несколько значений, все же является детерминированным, поэтому я считаю, что вы можете фильтровать ключи без проблем.Поскольку batch_number - последнее, что вы хотите отфильтровать, допускается любой тип выражения where.Я предполагаю, что у вас всегда есть department.

Обратите внимание, что материализованные представления влияют на производительность .Более конкретно, напишите производительность.Однако полезно читать производительность, а не ALLOW FILTERING.

ОБНОВЛЕНИЕ:

Порядок, указанный в конце материализованного представления, говорит batch_number, однако, он будет сначала заказывать department, затем employee, а затем batch_number, поэтому заказ batch_number специально не гарантируется.Насколько я знаю, нет никакого способа обойти это.Может быть предпочтительнее другое решение для базы данных.

ОБНОВЛЕНИЕ 2:

Как указано в цепочке рассылки Apache (см. Комментарии ниже), материализованные представления не считаются готовыми к работе.Тем не менее, Datastax считает их пригодными для использования при условии, что они позаботятся об использовании упомянутых передовых методов.Лично у меня не было никаких проблем с материализованными взглядами.Это, конечно, с простым кластером единого центра обработки данных и с учетом лучших практик, в которых упоминаются более сложные установки, в таких обстоятельствах они могут сломаться.

0 голосов
/ 09 ноября 2018

Вы можете использовать индекс на employee и даже удалить его из первичного ключа, если хотите. Вам нужно отказаться от использования IN, но вы можете разбить запрос и объединить результаты на стороне клиента.

CREATE TABLE tk.test_good(
    department      TEXT,
    batch_number    INT,
    employee        TEXT,
    hash            TEXT,
    PRIMARY KEY ((department), batch_number, hash)
)WITH CLUSTERING ORDER BY (batch_number DESC);

CREATE INDEX IF NOT EXISTS employee_idx ON tk.test_good ( employee );

select * from tk.test_good where department='dep1' and employee='Bart' and batch_number >= 2 limit 3;
select * from tk.test_good where department='dep1' and employee='Lucy' and batch_number >= 2 limit 3;
select * from tk.test_good where department='dep1' and employee='John' and batch_number >= 2 limit 3;

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

...