2

10 億個のヒストグラムを SQL に保存する必要があります。これらのヒストグラムには同一のバケットがありますが、カウントに非常に大きな変動がある可能性がありますが、ほとんどのバケットは多くの場合 0 です。

私の最初の試みは、各列がバケットを表すヒストグラムごとに行を持つことでした。

データ型には細心の注意を払っていますが、それでもテーブルは割り当てられたストレージを超えているように見えます。

より多くのハードウェアを要求する前に、MS SQL に値の範囲 (0 が最も一般的) を格納するための効率的なソリューションに誰かが遭遇したかどうか疑問に思っていました。

前もって感謝します。

合計。

4

4 に答える 4

6
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

これは、保守、ロード、およびエクスポートが比較的容易な典型的な正規化モデルです。

于 2013-03-11T17:45:03.470 に答える
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テーブルは常にクラスター化されているため、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
于 2013-03-12T10:22:40.563 に答える
1

他の状況下でこれを提案することは夢にも思いませんが、ここではスペースが最も重要な問題であるため、試してみることをお勧めします...

各ヒストグラムを単一の varchar フィールドに格納し、各バケットの金額を区切り文字で区切って保存すると効率的です。

「1,,23,,,789789789」は、最初のバケットで 1、2 番目で 0 などを意味します。

于 2013-03-12T08:55:25.017 に答える
1

実際、この問題はテーブルを 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各バケットの (またはバケット範囲の左側の境界を理解できる) です。

于 2016-12-08T07:07:33.893 に答える