Lindorm主键设计在数据分区和数据查询中很重要,本文介绍设计主键前需要考虑的一些问题以及设计示例。
问题考虑
- Q:主键是唯一的吗?
A:相同的主键在Lindorm中被认为是同一条数据的多个版本,查询时默认返回最新版本的数据,所以通常主键都需要保证唯一,除非用到多版本特性。
最佳设计示例:主键可以是一列,也可以是多列的组合。每个主键表示一条记录。[userid]
:表示主键只有一列,每个用户只有一条记录。[userid][orderid]
:表示主键为两列的组合,每个用户有多条记录。
- Q:满足哪种查询场景?
A:主键的设计限制了数据的查询方式,一条
SELECT
查询语句,Lindorm服务器端会编译为两种查询方式。- 根据完整的主键查询(get方式),例如
SELECT * FROM table WHERE userid='abc' AND orderid=123
。说明 get方式需要知道所有的主键列,即组成主键所有字段的值都是确定的。 - 根据主键的范围查询(scan方式),例如
SELECT * FROM table WHERE userid='abc' AND 123<orderid<456
。说明 scan方式需要指定第一列主键的范围,否则Lindorm默认会拒绝低效的全表扫描查询,具体详情请参见ALLOW FILTERING介绍。
最佳设计示例:在有限的查询方式下如何实现复杂查询?以下方法可以帮您实现。- 再新建一张表作为索引表。
- 查询条件给定非主键列范围,服务端会使用Filter过滤不需要的数据。
- 使用二级索引。
- 使用
ORDER BY
方法实现倒序(将新数据排在前面),例如SELECT * FROM table WHERE userid='abc' AND 123<orderid<456 ORDER BY orderid DESC
。说明 由于表字段原始顺序的倒序性能比正序性能差,如果大部分数据是倒序场景,可以体现在主键设计上,主键设计为[userid][orderid DESC]
。
- 根据完整的主键查询(get方式),例如
- Q:数据足够分散,会存在堆积的热点现象吗?
A:散列的目的是将数据分散到不同的分区,不至于产生热点使某一台服务器终止,其他服务器空闲,充分发挥分布式和并发的优势。
最佳设计示例:- 设计md5散列算法,主键设计为
[md5(userid).subStr(0,4)][userId][orderid]
。 - 设计反转,主键设计为
[reverse(userid)][orderid]
。 - 设计取模,主键设计为
[bucket][timestamp][hostname][log-event]; long bucket = timestamp % numBuckets
。 - 增加随机数,主键设计为
[userId][orderid][random(100)]
。
- 设计md5散列算法,主键设计为
- Q:主键可以再精简点吗?
A:精简的主键列可以减少数据量,提高数据查询和数据写入效率。
最佳设计示例:- 使用Long或Int代替String,例如
'2015122410' => Long(2015122410)
。 - 使用编码代替名称,例如
'淘宝'=> 'tb'
。
- 使用Long或Int代替String,例如
- Q:使用scan方式会查询出不需要的数据吗?
A:不会。Lindorm宽表SQL支持多种数据类型,每种数据类型单独编码,具体支持的数据类型请参见基础数据类型。
常见设计示例
- 日志类、时间序列数据。列举出三个场景设计主键。
- 查询某台机器某个指标某段时间内的数据,主键设计为
[hostname][log-event][timestamp]
。 - 查询某台机器某个指标最新的几条数据,主键设计为
[hostname][log-event][timestamp DESC]
。 - 查询的数据存在只有时间一个维度或某一个维度数据量巨大的情况,主键设计为
long bucket = timestamp % numBuckets; [bucket][timestamp][hostname][log-event]
。
- 查询某台机器某个指标某段时间内的数据,主键设计为
- 交易类数据。列举出四个场景设计主键。
- 查询某个卖家某段时间内的交易记录,主键设计为
[seller_id][timestamp][order_number]
。 - 查询某个买家某段时间内的交易记录,主键设计为
[buyer_id][timestamp][order_number]
。 - 根据订单号查询,主键设计为
[order_number]
。 - 查询中同时满足三张表,一张买家维度表主键设计为
[buyer_id][timestamp][order_number]
。一张卖家维度表主键设计为[seller_id][timestamp][order_number]
。一张订单索引表主键设计为[order_number]
。
- 查询某个卖家某段时间内的交易记录,主键设计为