具有MAX()和GROUP BY()效率的select是否会读取所有行

问题描述 投票:2回答:2

我有一个像这样的cassandra表:

create table messages
    (user_id int, peer_id int, send_on timestamp, message text, 
    PRIMARY KEY (user_id, peer_id, send_on))
    WITH CLUSTERING ORDER BY (peer_id ASC, send_on DESC);

并填充数据。

我想查询给定用户的每个peer_id的最新消息,我想出的是:

select peer_id, max(send_on), message 
  from messages 
  where user_id = 1 group by peer_id;

我想知道这是否会读取所有消息并且只提取最新消息或者它足够智能只能获取最新消息。

我问的原因是因为使用以下值填充表:

1, 1, now(), hello 1
1, 1, now(), hello 2
1, 1, now(), hello 3
1, 2, now(), hello 4
1, 2, now(), hello 5
1, 2, now(), hello 6
...
1, 3, now(), hello 9

当我运行查询时,我看到了预期的结果:

select peer_id, max(send_on), message from messages where user_id = 1 group by peer_id;

 peer_id | system.max(send_on)             | message
---------+---------------------------------+---------
       1 | 2019-04-13 19:20:48.567000+0000 | hello 3
       2 | 2019-04-13 19:21:07.929000+0000 | hello 6
       3 | 2019-04-13 19:21:22.081000+0000 | hello 9

(3 rows)

但是通过跟踪,我看到:

 activity                                                                                                                      | timestamp                  | source    | source_elapsed | client
-------------------------------------------------------------------------------------------------------------------------------+----------------------------+-----------+----------------+-----------
                                                                                                            Execute CQL3 query | 2019-04-13 19:24:54.948000 | 127.0.0.1 |              0 | 127.0.0.1
 Parsing select peer_id, max(send_on), message from messages where user_id = 1 group by peer_id; [Native-Transport-Requests-1] | 2019-04-13 19:24:54.956000 | 127.0.0.1 |           8812 | 127.0.0.1
                                                                             Preparing statement [Native-Transport-Requests-1] | 2019-04-13 19:24:54.957000 | 127.0.0.1 |          10234 | 127.0.0.1
                                                                    Executing single-partition query on messages [ReadStage-2] | 2019-04-13 19:24:54.962000 | 127.0.0.1 |          14757 | 127.0.0.1
                                                                                    Acquiring sstable references [ReadStage-2] | 2019-04-13 19:24:54.962000 | 127.0.0.1 |          14961 | 127.0.0.1
                                       Skipped 0/0 non-slice-intersecting sstables, included 0 due to tombstones [ReadStage-2] | 2019-04-13 19:24:54.962000 | 127.0.0.1 |          15211 | 127.0.0.1
                                                                       Merged data from memtables and 0 sstables [ReadStage-2] | 2019-04-13 19:24:54.963000 | 127.0.0.1 |          15665 | 127.0.0.1
                                                                          Read 9 live rows and 0 tombstone cells [ReadStage-2] | 2019-04-13 19:24:54.963000 | 127.0.0.1 |          15817 | 127.0.0.1
                                                                                                              Request complete | 2019-04-13 19:24:54.964448 | 127.0.0.1 |          16448 | 127.0.0.1

所以它似乎读取所有9行。有没有办法优化这个?也许改变我的架构?

cassandra cql cassandra-3.0
2个回答
0
投票

我能想到的两个选项是你可以创建另一个表作为每个userID和peerID的最大记录的索引。这两个字段将组成您的分区键,然后将包含您在该消息表中为该userID和peerID找到最大记录所需的其余数据。每当您将数据放入数据时,数据都会被上传,因此您始终只需将最新消息写入该表,它始终是最大值。您可以做的另一件事就是将最后一条消息完全存储在那里,然后您根本不需要在那里引用消息表来获取实际数据。我之前提到的相同分区键,也只是在那里写实际的消息。


0
投票

所以这是一个想法;将您的分区键更改为user_idpeer_id,然后您可以使用PER PARTITION LIMIT构造。那将只读回一行(每个分区),然后你也不必使用MAX,因为CLUSTERING ORDER BY (send_on DESC)第一行将是最新的:

> CREATE TABLE messages
    (user_id int, peer_id int, send_on timestamp, message text,
    PRIMARY KEY ((user_id, peer_id), send_on))
    WITH CLUSTERING ORDER BY (send_on DESC);

> SELECT peer_id, send_on, message
          FROM messages
          WHERE user_id = 1 AND peer_id=1
          PER PARTITION LIMIT 1;

 peer_id | send_on                         | message
---------+---------------------------------+---------
       1 | 2019-04-15 15:21:40.350000+0000 | hello 3

(1 rows)

> SELECT peer_id, send_on, message
          FROM messages PER PARTITION LIMIT 1;

 peer_id | send_on                         | message
---------+---------------------------------+---------
       3 | 2019-04-15 15:21:40.387000+0000 | hello 9
       2 | 2019-04-15 15:21:40.365000+0000 | hello 6
       1 | 2019-04-15 15:21:40.350000+0000 | hello 3

(3 rows)

注意:最后一个查询是一个多键查询,仅用于演示目的,显然不是在大型生产集群中完成的事情。

© www.soinside.com 2019 - 2024. All rights reserved.