最高效(存储空间)方式在SQL中存储直方图

时间:2013-03-11 17:21:47

标签: sql sql-server database-design

我需要在SQL中存储十亿个直方图。这些直方图具有相同的存储桶,但其计数可能有很大的变化,但是,大多数情况下,大多数存储桶都是0。

我最初的尝试是每个直方图有一行,每列代表一个桶。

我对我的数据类型一直非常小心,但表格看起来仍然超出为其分配的存储空间。

我想知道在我必须请求更多硬件之前,是否有人在MS SQL中遇到了存储值范围(其中0是最常见的)的有效解决方案。

提前致谢。

托特。

4 个答案:

答案 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个桶,你甚至可以使用tinyintBUCKET_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(或者我们可以理解铲斗范围的左边界)。