Cassandra-2.1.2 中的范围扫描花费大量时间
Range Scan in Cassandra-2.1.2 taking a lot of time
我的用例是这样的:我在 table 中插入 1000 万行,描述如下:
keyval bigint, rangef bigint, arrayval blob, PRIMARY KEY (rangef, keyval)
输入数据如下-
keyval - some timestamp
rangef - a random number
arrayval - a byte array
我将主键作为复合键,因为在插入 1000 万行后,我想对键值执行 运行ge 扫描。由于 keyval 包含时间戳,而且我的查询会像这样,请给我这次到这次之间的所有行。因此,要执行此类 Select 查询,我将主键作为复合键。
现在,在摄取的同时,表现非常好,令人满意。但是当我运行上面描述的查询时,性能很低。当我查询时 - 给我带来 t1 和 t1 + 3 分钟内的所有行,在 160 秒内返回了近 500k 条记录。
我的查询是这样的
Statement s = QueryBuilder.select().all().from(keySpace, tableName).allowFiltering().where(QueryBuilder.gte("keyval", 1411516800)).and(QueryBuilder.lte("keyval", 1411516980));
s.setFetchSize(10000);
ResultSet rs = sess.execute(s);
for (Row row : rs)
{
count++;
}
System.out.println("Batch2 count = " + count);
我使用的是默认分区程序,即 MurMur 分区程序。
我的集群配置是-
没有。节点数 - 4
种子节点数 - 1
磁盘数量 - 6
MAX_HEAP_SIZE 每个节点 = 8G
其余配置为默认。
如何提高我的 运行ge 扫描性能?
您实际上是在执行完整的 table 扫描,而不是范围扫描。这是 Cassandra 可能的最慢查询之一,通常仅由分析工作负载使用。如果在任何时候您的查询需要 allow filterting
用于 OLTP 工作负载,则很可能是错误的。基本上,Cassandra 在设计时就知道需要访问整个数据集的查询不会扩展,因此我们付出了大量努力来简化分区并快速访问分区内的数据。
要解决此问题,您需要重新考虑您的数据模型并考虑如何将数据限制为对单个分区的查询。
RussS 是正确的,您的问题是由使用 ALLOW FILTERING
引起的,而且您没有将查询限制在单个分区。
How I can improve my range scan performance?
通过使用分区键值限制查询。
PRIMARY KEY (rangef, keyval)
如果以上确实正确,那么rangef
就是您的分区键。将您的查询更改为首先限制 rangef
的特定值(如 RussS 建议的 "single partition")。那么您当前对集群键 keyval
的范围查询应该可以工作。
现在,该查询可能 return 对您没有任何用处。或者您可能必须在应用程序端迭代许多 rangef
值,这可能很麻烦。这是您需要重新评估数据模型并提出适当的键来对数据进行分区的地方。
I made secondary index on Keyval, and my query performance was improved. From 160 seconds, it dropped to 40 seconds. So does indexing Keyval field makes sense?
依赖二级索引的问题是,它们一开始可能看起来很快,但随着时间的推移会变慢。特别是对于像时间戳(Keyval)这样的高基数列,二级索引查询必须走到每个节点并最终扫描大量行以获得少量结果。在新查询 table 中复制数据总是比依赖二级索引查询更好。
我的用例是这样的:我在 table 中插入 1000 万行,描述如下:
keyval bigint, rangef bigint, arrayval blob, PRIMARY KEY (rangef, keyval)
输入数据如下-
keyval - some timestamp
rangef - a random number
arrayval - a byte array
我将主键作为复合键,因为在插入 1000 万行后,我想对键值执行 运行ge 扫描。由于 keyval 包含时间戳,而且我的查询会像这样,请给我这次到这次之间的所有行。因此,要执行此类 Select 查询,我将主键作为复合键。
现在,在摄取的同时,表现非常好,令人满意。但是当我运行上面描述的查询时,性能很低。当我查询时 - 给我带来 t1 和 t1 + 3 分钟内的所有行,在 160 秒内返回了近 500k 条记录。
我的查询是这样的
Statement s = QueryBuilder.select().all().from(keySpace, tableName).allowFiltering().where(QueryBuilder.gte("keyval", 1411516800)).and(QueryBuilder.lte("keyval", 1411516980));
s.setFetchSize(10000);
ResultSet rs = sess.execute(s);
for (Row row : rs)
{
count++;
}
System.out.println("Batch2 count = " + count);
我使用的是默认分区程序,即 MurMur 分区程序。
我的集群配置是-
没有。节点数 - 4 种子节点数 - 1 磁盘数量 - 6 MAX_HEAP_SIZE 每个节点 = 8G
其余配置为默认。
如何提高我的 运行ge 扫描性能?
您实际上是在执行完整的 table 扫描,而不是范围扫描。这是 Cassandra 可能的最慢查询之一,通常仅由分析工作负载使用。如果在任何时候您的查询需要 allow filterting
用于 OLTP 工作负载,则很可能是错误的。基本上,Cassandra 在设计时就知道需要访问整个数据集的查询不会扩展,因此我们付出了大量努力来简化分区并快速访问分区内的数据。
要解决此问题,您需要重新考虑您的数据模型并考虑如何将数据限制为对单个分区的查询。
RussS 是正确的,您的问题是由使用 ALLOW FILTERING
引起的,而且您没有将查询限制在单个分区。
How I can improve my range scan performance?
通过使用分区键值限制查询。
PRIMARY KEY (rangef, keyval)
如果以上确实正确,那么rangef
就是您的分区键。将您的查询更改为首先限制 rangef
的特定值(如 RussS 建议的 "single partition")。那么您当前对集群键 keyval
的范围查询应该可以工作。
现在,该查询可能 return 对您没有任何用处。或者您可能必须在应用程序端迭代许多 rangef
值,这可能很麻烦。这是您需要重新评估数据模型并提出适当的键来对数据进行分区的地方。
I made secondary index on Keyval, and my query performance was improved. From 160 seconds, it dropped to 40 seconds. So does indexing Keyval field makes sense?
依赖二级索引的问题是,它们一开始可能看起来很快,但随着时间的推移会变慢。特别是对于像时间戳(Keyval)这样的高基数列,二级索引查询必须走到每个节点并最终扫描大量行以获得少量结果。在新查询 table 中复制数据总是比依赖二级索引查询更好。