AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 184127
Accepted
Matt Camp
Matt Camp
Asked: 2017-08-23 17:20:00 +0800 CST2017-08-23 17:20:00 +0800 CST 2017-08-23 17:20:00 +0800 CST

允许过滤与不过滤;Cassandra 数据模型问题

  • 772

我在家里的一些 RaspberryPi 上运行了一个玩具 Cassandra 集群。我目前正在将 CryptoCoin 数据记录到其中,希望能更多地了解 Cassandra 以及沿途的其他一些事情。

我今天的问题是确定我是否在这张表上正确地构建了我的模式。

该表没有很多字段,主键是名称字段和时间戳字段。我想从所有硬币中查询最后 N 小时的数据(每分钟记录一次数据)。如果我使用简单的 WHERE 子句,我会收到“ALLOW FILTERING”警告。我理解它为什么会发生,但我正在努力理解正确的前进道路以确保可扩展的解决方案。现在该表只有大约 320k 条记录,我可以毫无问题地使用 ALLOW FILTERING,但我意识到这可能并非总是如此。

我设置了一个测试来查看运行两种不同的查询方法需要多长时间。ALLOW FILTERING 方法目前是最快的,但它可能会保持这种状态吗?这就是我缺乏知识的地方。

我有一个想法添加另一个字段,即星期几,也可能是一个月字段。想法是这可能允许在查询中进行更多过滤,因此我不必像下面那样遍历所有硬币,但我不知道这是否是个好主意。如果我这样做,我是否将它们设为 PrimaryKey?认为这是我与 Cassandra 最混淆的地方,但并非完全如此;也许只是不够自信。

CQL表说明:

CREATE TABLE cryptocoindb.worldcoinindex (
    name text,
    timestamp int,
    label text,
    price_btc double,
    price_cny double,
    price_eur double,
    price_gbp double,
    price_rur double,
    price_usd double,
    volume_24h double,
    PRIMARY KEY (name, timestamp)
) WITH CLUSTERING ORDER BY (timestamp ASC)
    AND bloom_filter_fp_chance = 0.01
    AND caching = {'keys': 'ALL', 'rows_per_partition': 'NONE'}
    AND comment = ''
    AND compaction = {'class': 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy', 'max_threshold': '32', 'min_threshold': '4'}
    AND compression = {'chunk_length_in_kb': '64', 'class': 'org.apache.cassandra.io.compress.LZ4Compressor'}
    AND crc_check_chance = 1.0
    AND dclocal_read_repair_chance = 0.1
    AND default_time_to_live = 0
    AND gc_grace_seconds = 864000
    AND max_index_interval = 2048
    AND memtable_flush_period_in_ms = 0
    AND min_index_interval = 128
    AND read_repair_chance = 0.0
    AND speculative_retry = '99PERCENTILE';

Python中的代码:

# First method using ALLOW FILTERING:
startTime = time.time()
oneDaySec = 60*60*24
prior24hr = int(time.time()-oneDaySec)

query = "SELECT * FROM {}.{} WHERE timestamp > {} ALLOW FILTERING;".format(CASSANDRA_DB, CASSANDRA_TABLE, prior24hr)

rslt = session.execute(query, timeout=None)
worldcoinindex = rslt._current_rows
elapseTime = time.time()-startTime

print("Elapsed Time for this method: {}".format(elapseTime))

此方法经过的时间:0.6223547458648682

# Second method using multiple queries...

startTime = time.time()

# I get the unique coin names here.
qryGetCoinList = "SELECT DISTINCT name FROM {}.{};".format(CASSANDRA_DB, CASSANDRA_TABLE)
rslt = session.execute(qryGetCoinList, timeout=None)
rsltGetCoinList = rslt._current_rows
rsltGetCoinList = rsltGetCoinList.name.tolist()

oneDaySec = 60*60*24
prior24hr = int(time.time()-oneDaySec)

# This iterates over the unique coin names and queries 
# the last 24 hrs worth of data per coin.
# NOTE: There are 518 unique coins.  

rsltTodayPrices = pd.DataFrame()
for coin in rsltGetCoinList:

    qryTodayPrices = """
                    SELECT * FROM {}.{} 
                    WHERE name = '{}' AND timestamp > {};
                    """.format(CASSANDRA_DB, 
                               CASSANDRA_TABLE, 
                               coin, 
                               prior24hr)
    rslt = session.execute(qryTodayPrices, timeout=None)
    TodayPrices = rslt._current_rows
    rsltTodayPrices.append(TodayPrices)

elapseTime = time.time()-startTime
print("Elapsed Time for this method: {}".format(elapseTime))

此方法经过的时间:1.4576539993286133

谢谢!

nosql schema
  • 1 1 个回答
  • 5963 Views

1 个回答

  • Voted
  1. Best Answer
    Aaron
    2017-08-26T09:28:47+08:002017-08-26T09:28:47+08:00

    现在该表只有大约 320k 条记录,我可以毫无问题地使用 ALLOW FILTERING,但我意识到这可能并非总是如此。

    所以事情是这样的:Cassandra非常擅长通过特定键查询数据。它还擅长检索分区内的一系列数据。

    "SELECT * FROM {}.{} WHERE timestamp > {} ALLOW FILTERING;"
    

    但是由于它的分布式特性,它并不擅长扫描整个表来编译结果集。这就是您要求它对上述查询进行的操作。

    网络流量很昂贵。因此,Cassandra 的主要目标是确保您的查询由单个节点提供服务。在ALLOW FILTERING不指定分区键(名称)的情况下使用时,您的查询需要一个协调节点,并检查集群中的每个节点是否有可能与您的 WHERE 子句匹配的值。

    本质上,集群中的节点越多,对ALLOW FILTERING性能的不利影响就越大(除非您至少指定分区键......只有这样才能保证您的查询可以由单个节点提供服务)。请注意,您较慢的查询实际上做到了这一点,并为您解决了这个问题。

    我有一个想法添加另一个字段,即星期几,也可能是一个月字段。

    这是个好主意!

    它解决了两个问题。

    1. 它确保您的查询将由单个节点提供服务。
    2. 它可以保护您的分区不会变得太大。

    Cassandra 每个分区有 20 亿个单元的限制。由于您的分区键是“名称”并且您不断在其中添加唯一的时间戳,因此您将朝着该限制前进,直到达到该限制,或者您的分区变得太大而无法使用(可能是后者)。

    以下是我将如何解决这个问题:

    CREATE TABLE cryptocoindb.worldcoinindex_byday (
        daybucket text,
        name text,
        datetime timestamp,
        label text,
        price_btc double,
        price_cny double,
        price_eur double,
        price_gbp double,
        price_rur double,
        price_usd double,
        volume_24h double,
        PRIMARY KEY (daybucket, datetime, name)
    ) WITH CLUSTERING ORDER BY (datetime DESC, name ASC);
    

    现在你可以这样查询:

    SELECT * FROM cryptocoindb.worldcoinindex
    WHERE daybucket='20170825' AND datetime > '2017-08-25 17:20';
    

    此外,通过按“日期时间”降序对行进行聚类,您可以确保最新数据位于每个单元格的顶部(使 Cassandra 无需解析)。

    我将“名称”移动到最后一个聚类列,只是为了保持唯一性。如果您永远不会按“名称”进行查询,那么将其用作分区键是没有意义的。

    希望这可以帮助。

    注意:我将您的更改timestamp int为,datetime timestamp因为它增加了示例的清晰度。您可以使用任何适合您的方式,但请注意以数据类型命名列所引起的混淆。

    编辑 20170826

    以下代码与您的代码相同还是不同?PRIMARY KEY ((daybucket, datetime), name)

    不,那不一样。那是使用一种称为复合分区键的东西。它会在集群中为您提供更好的数据分布,但会使您的查询更加困难,并且基本上会让您重新进行表扫描。

    对于 Cassandra 主键的良好、全面的描述,Carlo Bertuccini在 StackOverflow 上有很好的回答:

    https://stackoverflow.com/questions/24949676/difference-between-partition-key-composite-key-and-clustering-key-in-cassandra/24953331#24953331

    有没有办法改变 Cassandra 读取时间戳的方式,或者有一种简单的方法来更改整个数据字段以改变时间戳,以便正确读取它?

    并不真地。Cassandra 时间戳可能很难使用。它们以毫秒精度存储,但在查询时实际上并没有显示完整的精度。此外,作为 2.1 补丁之一,它会自动以 GMT 显示时间;所以这也会让人们感到困惑。如果您在应用程序端管理时间戳的方式适合您,请坚持下去。

    • 10

相关问题

  • Cassandra 的“phpMyAdmin”

  • PostgreSQL:表的创建日期

  • 有没有制作数据库设计和原型的好工具?[关闭]

  • 我的 Web 应用程序建模架构有多错误?

  • NoSQL 和传统的 RDBMS 有什么区别?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve