在 MemSQL 上使用列存储的稀疏矩阵
Sparse matrix using column store on MemSQL
我是列存储数据库系列的新手,有些概念对我来说还不是很清楚。我想用MemSQL来存储稀疏矩阵。
table 看起来像这样:
CREATE TABLE matrix (
r_id INT,
c_id INT,
cell_data VARCHAR(10),
KEY (`r_id`, `c_id`) USING CLUSTERED COLUMNSTORE,
);
查询:
SELECT c_id, cell_data FROM matrix WHERE r_id=<val>;
即整行
SELECT r_id, cell_data FROM matrix WHERE c_id=<val>;
即整列
SELECT cell_data FROM matrix WHERE r_id=<val1> AND c_id=<val2>;
即一个单元格
UPDATE matrix SET cell_data=<val> WHERE r_id=<val1> AND c_id=<val2>;
INSERT INTO matrix VALUES (<v1>, <v2>, <v3>);
查询 1 和 2 的频率差不多,3、4 和 5 的频率也差不多。 Q1,2 中的一个与 Q3,4,5 中的一个频率相同(即 Q1,2:Q3,4,5 ~= 1:1)。
我确实意识到,一次向列存储中插入一行会为每次插入创建行段组,从而降低性能。我无法批量插入。我也不能使用内存中的行存储(矩阵太大)。
我有三个问题:
如果仅更改 cell_data
(即第 4 季度),单行插入的问题是否也涉及更新?
是否可以在内存行 table 中执行插入(?和更新?)操作并定期将内容批处理到列 table ?
- 如果我需要最新数据 (?UNION ALL?),我将如何执行 Q1、2?
- 是否可以避免对两个 tables 执行 Q3(?这意味着两次往返?)?
我比较关心Q1和Q2的执行速度。聚簇键是否最适合那些。我不确定上面的table如何存储记录。
1。
是的,单行更新也表现不佳 - 它们本质上是删除和插入。
2。
是的,事实上我们在幕后自动执行此操作——最近插入的数据(如果行数太少而不能成为一个好的列段)保存在内存中的行存储形式中,读取查询本质上是查看 UNION ALL 该数据和面向列的数据。然后我们将这些数据批处理以写入面向列的形式。
如果这不够好,根据您的工作量,您可能会受益于明确地将一些数据保存在行存储中 table 而不是依赖上述行为,在这种情况下:
2a。是的,要查看最新数据,您将使用 UNION ALL
2b。数据可能在 table 中,因此您必须查询两者(例如对于 Q1、2,使用 UNION ALL 有效)。这不会进行两次往返,只有一次。
3。
您可以先在列存储键中按 r 或 c 排序 - 在当前模式中为 r。这使得对行的查询变得高效,但是对列的查询将非常低效,它们可能必须基本上扫描完整的 table (取决于数据中的模式)。不幸的是 columnstore tables 不支持使用多个键,所以没有好的方法来解决这个问题。一种潜在的 hacky 解决方案是维护 table 的两份副本,一份使用密钥 (r, c),一份使用密钥 (c, r) - 这实际上是手动维护两个索引。
根据您描述的工作负载,听起来您正在执行许多单行查询(Q3、4、5,占工作负载的 50%),行存储比列存储更适合(参见 http://docs.memsql.com/latest/concepts/columnstore/)。不幸的是,如果它不适合内存,除了添加更多内存之外没有真正解决这个问题的好方法。
我是列存储数据库系列的新手,有些概念对我来说还不是很清楚。我想用MemSQL来存储稀疏矩阵。
table 看起来像这样:
CREATE TABLE matrix (
r_id INT,
c_id INT,
cell_data VARCHAR(10),
KEY (`r_id`, `c_id`) USING CLUSTERED COLUMNSTORE,
);
查询:
SELECT c_id, cell_data FROM matrix WHERE r_id=<val>;
即整行SELECT r_id, cell_data FROM matrix WHERE c_id=<val>;
即整列SELECT cell_data FROM matrix WHERE r_id=<val1> AND c_id=<val2>;
即一个单元格UPDATE matrix SET cell_data=<val> WHERE r_id=<val1> AND c_id=<val2>;
INSERT INTO matrix VALUES (<v1>, <v2>, <v3>);
查询 1 和 2 的频率差不多,3、4 和 5 的频率也差不多。 Q1,2 中的一个与 Q3,4,5 中的一个频率相同(即 Q1,2:Q3,4,5 ~= 1:1)。
我确实意识到,一次向列存储中插入一行会为每次插入创建行段组,从而降低性能。我无法批量插入。我也不能使用内存中的行存储(矩阵太大)。
我有三个问题:
如果仅更改
cell_data
(即第 4 季度),单行插入的问题是否也涉及更新?是否可以在内存行 table 中执行插入(?和更新?)操作并定期将内容批处理到列 table ?
- 如果我需要最新数据 (?UNION ALL?),我将如何执行 Q1、2?
- 是否可以避免对两个 tables 执行 Q3(?这意味着两次往返?)?
我比较关心Q1和Q2的执行速度。聚簇键是否最适合那些。我不确定上面的table如何存储记录。
1。 是的,单行更新也表现不佳 - 它们本质上是删除和插入。
2。 是的,事实上我们在幕后自动执行此操作——最近插入的数据(如果行数太少而不能成为一个好的列段)保存在内存中的行存储形式中,读取查询本质上是查看 UNION ALL 该数据和面向列的数据。然后我们将这些数据批处理以写入面向列的形式。
如果这不够好,根据您的工作量,您可能会受益于明确地将一些数据保存在行存储中 table 而不是依赖上述行为,在这种情况下:
2a。是的,要查看最新数据,您将使用 UNION ALL
2b。数据可能在 table 中,因此您必须查询两者(例如对于 Q1、2,使用 UNION ALL 有效)。这不会进行两次往返,只有一次。
3。 您可以先在列存储键中按 r 或 c 排序 - 在当前模式中为 r。这使得对行的查询变得高效,但是对列的查询将非常低效,它们可能必须基本上扫描完整的 table (取决于数据中的模式)。不幸的是 columnstore tables 不支持使用多个键,所以没有好的方法来解决这个问题。一种潜在的 hacky 解决方案是维护 table 的两份副本,一份使用密钥 (r, c),一份使用密钥 (c, r) - 这实际上是手动维护两个索引。
根据您描述的工作负载,听起来您正在执行许多单行查询(Q3、4、5,占工作负载的 50%),行存储比列存储更适合(参见 http://docs.memsql.com/latest/concepts/columnstore/)。不幸的是,如果它不适合内存,除了添加更多内存之外没有真正解决这个问题的好方法。