我需要在SQL中存储十亿个直方图。这些直方图具有相同的存储桶,但其计数可能有很大的变化,但是,大多数情况下,大多数存储桶都是0。
我最初的尝试是每个直方图有一行,每列代表一个桶。
我对我的数据类型一直非常小心,但表格看起来仍然超出为其分配的存储空间。
我想知道在我必须请求更多硬件之前,是否有人在MS SQL中遇到了存储值范围(其中0是最常见的)的有效解决方案。
提前致谢。
托特。
答案 0 :(得分:5)
CREATE TABLE Histogram (
HistogramID BIGINT /* INT only goes to 2bn */ IDENTITY NOT NULL CONSTRAINT PK_Histogram PRIMARY KEY
-- Other metadata like the date and time or whatever
)
CREATE TABLE Bucket (
BucketID INT /* or smaller */ IDENTITY NOT NULL CONSTRAINT PK_Bucket PRIMARY KEY
-- Other metadata like the range it applies to
)
CREATE TABLE HistogramValue (
HistogramID BIGINT NOT NULL
,BucketID INT NOT NULL
,Counter BIGINT /* or smaller datatype */ NOT NULL
,CONSTRAINT PK_HistogramValue PRIMARY KEY (HistogramID, BucketID)
,CONSTRAINT FK_Histogram FOREIGN KEY REFERENCES Histogram(HistogramID)
,CONSTRAINT FK_Bucket FOREIGN KEY REFERENCES Bucket(BucketID)
)
HistogramValue
表格稀疏。您可以将Bucket
表的连接保留到特定直方图的HistogramValue
表中,以获得“整个”直方图:
SELECT b.Range
,COALESCE(hv.Counter, 0) AS Counter
FROM Bucket b
LEFT JOIN HistogramValue hv
ON hv.HistogramID = @HistogramID
AND hv.BucketID = b.BucketID
这是一个典型的标准化模型,相对容易维护,加载和导出。
答案 1 :(得分:2)
从数据管理的角度来看直方图原子吗?我的意思是:你总是把整个直方图读或写成数据库中不可分割的单位吗?
如果是,只需将其序列化为BLOB即可。在写入BLOB之前,您甚至可以通过一些压缩库进行滑动,这是一个很好的衡量标准。
如果否,请考虑使用以下内容:
CREATE TABLE HISTOGRAM (
HISTOGRAM_ID int PRIMARY KEY
-- Other fields...
);
CREATE TABLE HISTOGRAM_VALUE (
HISTOGRAM_ID int REFERENCES HISTOGRAM (HISTOGRAM_ID),
BUCKET_NO smallint,
VALUE decimal NOT NULL, -- Or whatever type is appropriate.
PRIMARY KEY (HISTOGRAM_ID, BUCKET_NO)
);
(注意:如果你绝对肯定你永远不会需要超过256个桶,你甚至可以使用tinyint
来BUCKET_NO
来挤出更多的空间效率。 )
请记住InnoDB tables are always clustered,因此上面的HISTOGRAM_VALUE
表只是一个B树,没有表堆或其他B树(因为没有二级索引 - 外键)可以直接满足主要索引)。这与存储方式一样,与InnoDB表一样。
为了节省空间,只需省略具有0值的存储桶,除非直方图以这样的存储桶开始或结束。例如......
0 0 14.7 -12.9 0 0 55.1 0 0 0
......可以表示为:
HISTOGRAM_ID BUCKET_NO VALUE
1 1 0
1 3 14.7
1 4 -12.9
1 7 55.1
1 10 0
答案 2 :(得分:1)
我绝不会梦想在任何其他情况下暗示这一点,但由于空间是最重要的问题,你可能想要试验它......
将每个直方图存储在单个varchar字段中可能是有效的,每个存储区中的数量由一些分隔符分隔,例如
“1 ,, 23 ,,, 789789789”在第一个桶中表示1,在第二个桶中表示0,依此类推。
答案 3 :(得分:1)
实际上,我们可以通过只创建一个表来解决这个问题。如果创建多个表,我们必须使用join
运算符。当我们需要使用它时,获得我们想要的histogram
是无效的。
CREATE TABLE HISTOGRAM_VALUE
{
HISTOGRAM_ID INT,
BUCKET_ID INT,
BUCKET_MIN_VALUE INT, //or whatever value type you want
BUCKET_HEIGHT INT,
// other metadata
PRIMARY KEY(HISTOGRAM_ID,BUCKET_ID,BUCKET_MIN_VALUE)
};
BUCKET_MIN_VALUE
是每个桶的min_value
(或者我们可以理解铲斗范围的左边界)。