0

下の図では、私がやろうとしていることの単純化されたバージョンを見ることができます。特定のアイテムの場所を追跡する必要がありますが、特定のアイテムの最新の場所を効率的に取得する必要もあります。これを行う最も簡単な方法は、ItemLocationLog にクエリを実行し、そのアイテムの最新の日付を検索することですが、このテーブルは非常に大きくなる可能性があるため、これが効率的かどうか疑問に思っています (dateTime フィールドのインデックス作成が役立つと思います)。 、しかし、どのくらいかを判断する経験がありません)。

私が考えたもう 1 つの方法は、Item にログ テーブルの外部キーを追加することです (「lastLocation」フィールドの図に示されているように)。これは常に最新のログ エントリを指すため、検索の手間が省けます。 . さらに別のオプションとして、Item の Location に外部キーを追加し、任意のアイテムにログ エントリが追加されるたびにそれを更新する方法があります。

これは単純な解決策でよくある問題だと確信していますが、私はこれを経験したことがないので、自分のアプローチには懐疑的です。このタイプのシナリオのベスト プラクティスは何ですか? コストのかかるクエリを回避するために Item テーブルへの参照を追加しても問題ありませんか、それとも、ログ テーブル自体からこの情報を取得するだけの簡単なクエリですか?

データベース モデル

4

3 に答える 3

4

原則として、モデルに冗長性を含めるのは、パフォーマンスを測定し、実際のボトルネックを特定し、非正規化が実際に役立つと結論付けた場合 (データ破損のリスクを相殺するのに十分) に限ってください。

不思議なことに、あなたの場合はそうではありません。B ツリー インデックスの動作の特徴の 1 つは、MAX の検索が正確な値の検索と本質的に同じくらい高速であることです。INT が DBMS の DATETIME よりも小さい場合は、キャッシングが改善されて少しは向上する可能性がありますが、それほど大きくはありません。

インデックス作成は、正しく行われれば非常に強力です。そして index onItemLocationLog {idItem, dateTime}は超高速を促進するはずですSELECT MAX(dateTime) FROM ItemLocationLog WHERE idItem = ?

Use The Index を見てみましょう、ルーク! トピックの素敵な紹介のために。

于 2012-05-09T20:07:52.123 に答える
1

自分が抱えていることを知らない問題に対して事前に最適化しないでください。

ItemLocationLogをカバーするテーブルのインデックスから始めますidItem。次にSELECT TOP 1 idItemLocationLog from ItemLocationLog order by idItemLocationLog DESC-PKが自動インクリメント列であると仮定します。 これが十分に高速でない場合は、 plus でインデックスを試しidItemくださいdateTimeそれでも十分に高速でない場合は、最後の既知の位置参照を に保持するなど、抜本的な非正規化を検討し始めることができますItem

一部の人々は、RDBMS がデータを取得するのにどれほど優れているかに本当に驚いています。あなたはすべきではありません!

于 2012-05-09T19:48:44.090 に答える
1

最初にこれを試してください (例は PostgeSQL 用です)。

ここに画像の説明を入力

-- Latest location of ItemID = 75
select
      a.ItemID
    , b.LocationID
    , ValidFrom
from Item         as a
join ItemLocation as b on b.ItemID     = a.ItemID
                      and b.ValidFrom  = (select max(x.ValidFrom) from ItemLocation as x
                                                                  where x.ItemID = a.ItemID) 
join Location     as c on b.LocationID = c.LocationID
where a.ItemID = 75 ;


-- Earliest location of ItemID = 75
select
      a.ItemID
    , b.LocationID
    , ValidFrom
from Item         as a
join ItemLocation as b on b.ItemID     = a.ItemID
                      and b.ValidFrom  = (select min(x.ValidFrom) from ItemLocation as x
                                                                  where x.ItemID = a.ItemID) 
join Location     as c on b.LocationID = c.LocationID
where a.ItemID = 75 ;

これは恐ろしく見えるかもしれませんが、非常に高速です。ItemID主キーの一部です。

ここに画像の説明を入力

そして、いつでもすべてのアイテムのリストが必要な場合

-- Location of all items for point in time ('2012-05-01 11:00:00') 
select
      a.ItemID
    , b.LocationID
    , ValidFrom
from Item         as a
join ItemLocation as b on b.ItemID     = a.ItemID
                      and b.ValidFrom  = (select max(x.ValidFrom)
                                            from ItemLocation as x
                                           where x.ItemID = a.ItemID
                                             and x.ValidFrom <= '2012-05-01 11:00:00') 
join Location     as c on c.LocationID = b.LocationID
;

ここに画像の説明を入力

于 2012-05-09T21:17:53.110 に答える