sql >> データベース >  >> RDS >> Mysql

時間属性に関連する設計データベース

    これがあなたの述べた要件を達成するためのモデルです。

    時系列データモデルへのリンク

    IDEF1X表記へのリンク リレーショナルモデリング標準に慣れていない人のために。

    • 5NFに正規化。重複する列はありません。更新の異常やヌルはありません。

    • 製品のステータスが変更されたら、現在のDateTimeを使用してProductStatusに行を挿入するだけです。前の行に触れる必要はありません(これは真実であり、真実のままです)。 (アプリ以外の)ツールを報告するダミー値を解釈する必要はありません。

    • DateTimeは、製品がそのステータスに置かれた実際のDateTimeです。必要に応じて、「From」。 「宛先」は簡単に導き出すことができます。これは、製品の次の(DateTime>「From」)行のDateTimeです。存在しない場合、値は現在の日時です(ISNULLを使用)。

    最初のモデルが完成しました。 (ProductId、DateTime)は、主キーに一意性を提供するのに十分です。ただし、特定のクエリ条件の速度を要求するため、物理レベルでモデルを拡張し、以下を提供できます。

    • インデックス(すでにPKインデックスがあるので、2番目のインデックスを追加する前に最初に拡張します)は、対象となるクエリ({ProductId | DateTime | Status}の任意の配置に基づくクエリは、データ行に移動します)。これにより、Status ::ProductStatusの関係が非識別(破線)から識別タイプ(実線)に変更されます。

    • PK配置は、Product⇢DateTime⇢Statusに基づいて、ほとんどのクエリが時系列になることに基づいて選択されます。

    • 2番目のインデックスは、ステータスに基づくクエリの速度を向上させるために提供されています。

    • 代替配置では、それは逆になります。つまり、ほとんどの場合、すべての製品の現在のステータスが必要です。

    • ProductStatusのすべてのレンディションで、セカンダリインデックス(PKではない)のDateTime列はDESCendingです。最新のものが最初です。

    私はあなたが要求した議論を提供しました。もちろん、妥当なサイズのデータ​​セットを試して、独自の決定を行う必要があります。ここにわからないことがありましたら、お問い合わせください。拡大させていただきます。

    コメントへの回答

    現在の状態が2のすべての製品を報告する

    SELECT  ProductId,
            Description
        FROM  Product       p,
              ProductStatus ps
        WHERE p.ProductId = ps.ProductId  -- Join
        AND   StatusCode  = 2             -- Request
        AND   DateTime    = (             -- Current Status on the left ...
            SELECT MAX(DateTime)          -- Current Status row for outer Product
                FROM  ProductStatus ps_inner
                WHERE p.ProductId = ps_inner.ProductId
                )
    • ProductId インデックス付き、先頭の列、両側

    • DateTime インデックス付き、対象クエリオプションの2番目の列

    • StatusCode インデックス付き、対象クエリオプションの3列目

    • StatusCode以降 インデックスが降順である場合、内部クエリを満たすために必要なフェッチは1つだけです

    • 1つのクエリに対して、行が同時に必要です。それらは互いに接近しています(Clstered Indexによる)。行サイズが短いため、ほとんどの場合、同じページに表示されます。

    これは通常のSQL、サブクエリであり、SQLエンジンのパワーであるリレーショナルセット処理を使用します。これは1つの正しい方法です 、これ以上速いものはなく、他の方法は遅くなります。どのレポートツールでも、数回クリックするだけで、入力せずにこのコードを生成できます。

    ProductStatusの2つの日付

    DateTimeFromやDateTimeToなどの列は重大なエラーです。重要度の高い順に見ていきましょう。

    1. これは重大な正規化エラーです。 「DateTimeTo」は、次の行の単一のDateTimeから簡単に導出できます。したがって、冗長であり、列が重複しています。

      • 精度は考慮されていません。これは、DataType(DATE、DATETIME、SMALLDATETIME)によって簡単に解決されます。 1秒未満、マイクロ秒、またはナノ秒のいずれを表示するかは、ビジネス上の決定事項です。保存されているデータとは何の関係もありません。
    2. DateTo列の実装は、(次の行のDateTimeと)100%重複しています。これにはディスク容量の2倍かかります 。大きなテーブルの場合、それはかなりの不要な無駄になります。

    3. 短い行であるため、論理的および物理的なI/Oの2倍が必要になります。 アクセスするたびに、表を読みます。

    4. そして2倍のキャッシュスペース (言い換えると、特定のキャッシュスペースに収まる行数は半分になります)。

    5. 重複する列を導入することにより、エラーの可能性が導入されました(値は、重複するDateTimeTo列または次の行のDateTimeFromから2つの方法で導出できるようになりました)。

    6. これは更新の異常でもあります 。 DateTimeFrom Updatedを更新するときは、前の行のDateTimeToをフェッチして(近くにあるので大したことはありません)、更新する必要があります(回避できる追加の動詞なので大したことです)。

    7. 「短い」と「コーディングショートカット」は関係ありません。SQLは面倒なデータ操作言語ですが、SQLだけがあります (それに対処するだけです)。サブクエリをコーディングできない人は、実際にはコーディングしないでください。マイナーなコーディングの「難しさ」を緩和するために列を複製する人は、実際にはデータベースをモデリングするべきではありません。

    最高次のルール(正規化)が維持されている場合は、低次の問題のセット全体が排除されることに注意してください。

    セットの観点から考える

    • 単純なSQLを作成するときに「困難」を抱えたり、「苦痛」を経験したりする人は、職務を遂行する上で不自由になります。通常、開発者はそうではありません セットの観点から考える リレーショナルデータベースはセット指向モデルです 。

    • 上記のクエリでは、CurrentDateTimeが必要です。 ProductStatusはセットであるため 時系列の製品状態の場合、セットの最新またはMAX(DateTime)が必要です。 製品に属します。

    • 次に、セットの観点から、「難しい」とされるものを見てみましょう。 。各商品が特定の状態にあった期間のレポートの場合:DateTimeFromは使用可能な列であり、水平方向のカットオフ、サブセットセットを定義します。 (以前の行を除外できます); DateTimeToは、サブセットセットの最も早いものです。 製品の状態の。

    SELECT               ProductId,
                         Description,
            [DateFrom] = DateTime,
            [DateTo]   = (
            SELECT MIN(DateTime)                        -- earliest in subset
                FROM  ProductStatus ps_inner
                WHERE p.ProductId = ps_inner.ProductId  -- our Product
                AND   ps_inner.DateTime > ps.DateTime   -- defines subset, cutoff
                )
        FROM  Product       p,
              ProductStatus ps
        WHERE p.ProductId = ps.ProductId 
        AND   StatusCode  = 2             -- Request
    • 次の行を取得するという観点から考える 行指向であり、ではありません セット指向の処理。セット指向のデータベースで作業する場合の不自由。 Optimiserにすべてのことを考えさせてください。 SHOWPLANを確認してください。これにより、美しく最適化されます。

    • セットで考えることができない したがって、単一レベルのクエリのみの記述に限定されるため、次の理由は合理的ではありません。データベースに大規模な複製と更新異常を実装する。オンラインリソースとディスクスペースを浪費する。半分のパフォーマンスを保証します。簡単に導出できるデータを取得するための単純なSQLサブクエリの記述方法を学ぶ方がはるかに安価です。



    1. MYSQLデータベースのすべての外部キーを削除します

    2. #1060-列名'id'が重複しています

    3. Postgresqlは各IDの最後の行を抽出します

    4. Django:月ごとのクエリグループ