请考虑下表,该表记录了属于不同类别的不同公司的不同产品的价格变化。
Column | Type | Modifiers
-----------------+--------+-----------
category_id | bigint | not null
product_id | bigint | not null
industry_id | bigint | not null
time | bigint | not null
price | bigint | not null
product_info | json | not null
Indexes:
"price_change_pk" PRIMARY KEY, btree (category_id, product_id, price, "time")
Foreign-key constraints:
"orders_industry_id" FOREIGN KEY (industry_id) REFERENCES industry_info(industry_id)
"orders_product_id" FOREIGN KEY (product_id) REFERENCES device_info(product_id)
"orders_category_id" FOREIGN KEY (categoy_id) REFERENCES category_info(category_id)
为清楚起见,列值将为:
category_id
-一个单独的表将具有映射到类别名称的ID(唯一的bigint值)-类别的100s
(电子,时尚,健康,运动,玩具,书籍)
industry_id
-一个单独的表将具有映射到行业名称的id(唯一的bigint值)-一个类别中有数千个行业
(诺基亚,苹果,微软,PeterEngland,Rubik,Nivia,中远)
product_id
-一个单独的表将具有映射到产品名称的id(唯一的bigint值)-一个行业中数以百万计的产品
time
(unix时间为bigint)-修改价格的时间,
price
-几千个不同的值-(200、10000、14999、30599、450)
product_info
-包含产品额外信息的json(键/值对的数量可能会有所不同)
{seller:"ABC Assured", discount:10, model:XYZ, EMIoption:true, EMIvalue:12, festival_offer:28, market_stat:comingsoon}
以多种方式查询该表,以图表的形式分析日/周/月,小时/天/周/月范围内的产品价格变化趋势。趋势可能基于否。产品,正在修改的独特产品。
按原样存储JSON(如string
)会占用更多存储空间。因此,我尝试将键值和递增的序列ID存储在json中的单独表中,并使用这些ID。
喜欢
Keys (citext, bigint)
seller - 1
discount - 2
model - 3
EMIoption - 4
EMIvalue - 5
festival_offer - 6
...
...
currency - 25
Values (citext, bigint)
ABC Assured - 1
10 - 2
XYZ - 3
true - 4
12 - 5
28 - 6
comingsoon - 7
...
...
ZYX - 106
rupees - 107
american dollars - 108
canadian dollars - 109
Prime seller - 110
{seller:"ABC Assured", discount:10, model:XYZ, EMIoption:true, EMIvalue:12, festival_offer:28, market_stat:comingsoon, curreny: rupees}
成为
{"1":1, "2":2", "3":3, "4":4, "5":5, "6":6, "7":7, "25":107}
{seller:"Prime seller", discount:10, model:XYZ, EMIoption:true, EMIvalue:12, festival_offer:28, market_stat:comingsoon, curreny: "canadian dollars"}
成为
{"1":110, "2":2", "3":3, "4":4, "5":5, "6":6, "7":7, "25":109}
对于大约2000万个数据集,它减少了约1.5GB。
增加键值基数,增加序列号。所以我尝试将十进制存储为十六进制。
{"1":1, "2":2", "3":3, "4":4, "5":5, "6":6, "7":7, "25":107}
成为
{"1":1, "2":2", "3":3, "4":4, "5":5, "6":6, "7":7, "19":"6B"}
{"1":110, "2":2", "3":106, "4":4, "5":5, "6":6, "7":7, "25":109}
成为
{"1":, "2":2", "3":"6A", "4":4, "5":5, "6":6, "7":7, "19":"6D"}
将这些十进制整数存储为十六进制整数也是如此。
在普通的psql应用程序中,查询需要几分钟才能完成。由于它符合时间序列数据,因此我们使用TimescaleDB扩展,它的分片机制可以提高查询的执行速度,但我们需要几秒钟的结果。
查询样本: 要查看将给定类别中的所有产品每天按月分组的价格更改为500次的次数。
select count(*), to_char(date_trunc('day', to_timestamp(time/1000) at time zone 'Asia/Kolkata'), 'YYYY/MM/DD') as unit, price
from price_change
where category_id = 1000000010 and time between 1514745000000 and 1517423400000
and price = 500
group by price, unit;
要查看在过去10个月的每个月中,给定类别中所有产品的价格更改为(100,200,300,400,500,600,700,800,900,1000)中的任何一个的次数。
select count(*), to_char(date_trunc('month', to_timestamp(time/1000) at time zone 'Asia/Kolkata'), 'YYYY/MM/DD') as unit, price
from price_change
where category_id = 1000000010 and time between 1514745000000 and 1517423400000
and price in (100,200,300,400,500,600,700,800,900,1000) group by price, unit;
要选择在给定时间范围内在给定类别中价格已更改的产品详细信息
select product_id, product_name, price, to_char(date_trunc('day', to_timestamp(time/1000) at time zone 'Asia/Kolkata'), 'YYYY/MM/DD') as timestamp
from price_change
join products using product_id
where price_change.category_id = 1000000010
and price_change.time between 1514745000000 and 1517423400000;
要在给定的时间范围内选择给定类别中价格已更改的行业和产品ID详细信息
select industry_id, product_id, price
from price_change
join industries using industry_id
where price_change.category_id = 1000000010
and price_change.time between 1514745000000 and 1517423400000;
要在特定类别的折扣为10%的时间范围内选择产品价格变化的详细信息
select product_id, product_name, price, to_char(date_trunc('day', to_timestamp(time/1000) at time zone 'Asia/Kolkata'), 'YYYY/MM/DD') as timestamp
from price_change
join products using product_id
where price_change.category_id = 1000000010
and price_change.time between 1514745000000 and 1517423400000
and product_info->>'discount'=10;
要选择特定卖家在特定类别销售的时间范围内的产品价格更改明细
select product_id, product_name, price, to_char(date_trunc('day', to_timestamp(time/1000) at time zone 'Asia/Kolkata'), 'YYYY/MM/DD') as timestamp
from price_change
join products using product_id
where price_change.category_id = 1000000010
and price_change.time between 1514745000000 and 1517423400000
and product_info->>'seller'='ABC Assured';
在大多数情况下,查询的选择列中将不包含category_id
。
答案 0 :(得分:0)
如果您还提供一些有关通常查询内容的示例,则将有所帮助。有多种优化索引的方法/如何将数据写入磁盘的方式很大程度上取决于您正在运行的查询类型(更具体地说,where子句中的查询)?如果您使用的是用于JSON的where子句,则应考虑将其分解为列,或在JSON本身上建立索引。
听起来您的关注点之一是存储。因为TimescaleDB和PostgreSQL是关系型的,所以它们占用的存储空间比可能具有更好压缩特性的列式存储空间要多。您可以考虑使用ZFS之类的东西来压缩东西。