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

データベース:アクションのログを作成し、さまざまな参照を処理する方法は?

    以下は私がそれを行う方法です。スキーマを見た後、下部にもう少しコメントがあります。

    ログ

    LogID-一意のログID

    時間-イベントの日付/時間

    LogType-文字列またはID

    (サイドコメント、ここではIDを使用して、以下に示すメッセージテーブルを使用できるようにしますが、クイックnダーティが必要な場合は、ログ時間ごとに一意の文字列を使用できます(例:「ゲーム開始」、「メッセージ送信」)。 、など)

    LogActor

    LogID-外部キー

    LogActorType-文字列またはID(上記のように、IDの場合はルックアップテーブルが必要になります)

    LogActorID-これは、ユーザー、グループ、ゲームなどのタイプのテーブルに対する一意のIDです

    シーケンス-これはアクターの順序です。

    LogMessage

    LogType-外部キー

    メッセージ-長い文字列(varchar(max)?)

    言語-string(5)なので、「US-en」などの別の言語をキーオフできます

    サンプルデータ(3つの例を使用)

    ログ

    ID  Time   LogType 
    1   1/1/10 1
    2   1/1/10 2
    3   1/1/10 3
    

    LogActor

    LogID LogActorType LogActorID Sequence
    1     User         1          1
    1     User         2          2
    2     User         1          1
    2     User         2          2
    2     User         2          3
    2     Game         1          4
    3     User         3          1
    3     Group        1          2
    

    LogMessage

    LogType Message 
    1       {0} Made a new friend {1}
    2       {0}, {1}, {2} played a game ({3})
    3       {0} joined a group ({1})
    

    ユーザー

    ID Name
    1  User A
    2  User B
    3  User C
    

    ゲーム

    ID Name
    1  Name of game
    

    グループ

    ID Name
    1  Name of group
    

    ですから、このデザインの良いところは次のとおりです。

    • 拡張は非常に簡単です

    • アクターに関係なく多言語の問題を処理します

    • これは自己文書化であり、LogMessageテーブルは、保存しているデータが何を言うべきかを正確に説明しています。

    それについてのいくつかの悪いこと。

    • メッセージを読むには、複雑な処理を行う必要があります。

    • DBを見て、何が起こったのかを確認することはできません。

    私の経験では、この種の設計の良い部分は悪い部分を上回っています。ログをすばやく汚く見ることができるようにするために私が行ったことは、背面から何が起こっているかを確認する必要があるときに表示できるビュー(アプリケーションコードには使用しません)を作成することです。終了します。

    ご不明な点がありましたらお知らせください。

    更新-クエリの例

    私の例はすべてsqlserver2005+にあります。ターゲットにしたい別のバージョンがあるかどうか、お知らせください。

    LogActorテーブルを表示します(これを行うにはいくつかの方法がありますが、最適な方法は、データの配布、ユースケースなど、多くのことに依存します)ここに2つあります:

    a)

    SELECT 
      LogId,
      COLLESCE(U.Name,Ga.Name,Go.Name) AS Name,
      Sequence
    FROM LogActor A
    LEFT JOIN User U ON A.LogActorID = U.[ID] AND LogActorType = "User"
    LEFT JOIN Game Ga ON A.LogActorID = Ga.[ID] AND LogActorType = "Game"
    LEFT JOIN Group Go ON A.LogActorID = Go.[ID] AND LogActorType = "Group"
    ORDER BY LogID, Sequence
    

    b)

    SELECT 
      LogId,
      U.Name AS Name,
      Sequence
    FROM LogActor A
    INNER JOIN User U ON A.LogActorID = U.[ID] AND LogActorType = "User"
    UNION ALL
    SELECT 
      LogId,
      Ga.Name AS Name,
      Sequence
    FROM LogActor A
    INNER JOIN Game Ga ON A.LogActorID = Ga.[ID] AND LogActorType = "Game"
    UNION ALL
    SELECT 
      LogId,
      Go.Name AS Name,
      Sequence
    FROM LogActor A
    INNER JOIN Group Go ON A.LogActorID = Go.[ID] AND LogActorType = "Group"
    ORDER BY LogID, Sequence
    

    一般に、a)はb)よりも優れていると思います。たとえば、アクタータイプがない場合は、a)それを(null名で)含めます。ただし、b)は保守が簡単です(UNION ALLステートメントによってモジュール化が進むため)。これを行う方法は他にもあります(CTE、ビューなど)。私はb)のようにそれを行う傾向があり、私が見たところ、それはベストプラクティスではないにしても少なくとも標準的なプラクティスのようです。

    したがって、ログの最後の10項目は次のようになります。

    SELECT 
      LogId,
      M.Message,
      COLLESCE(U.Name,Ga.Name,Go.Name) AS Name,
      Time,
      A.Sequence
    FROM Log
    LEFT JOIN LogActor A ON Log.LogID = A.LogID
    LEFT JOIN User U ON A.LogActorID = U.[ID] AND LogActorType = "User"
    LEFT JOIN Game Ga ON A.LogActorID = Ga.[ID] AND LogActorType = "Game"
    LEFT JOIN Group Go ON A.LogActorID = Go.[ID] AND LogActorType = "Group"
    LEFT JOIN LogMessage M ON Log.LogType = M.LogMessage
    WHERE LogID IN (SELECT Top 10 LogID FROM Log ORDER BY Date DESC)
    ORDER BY Date, LogID, A.Sequence
    

    注意-ご覧のとおり、これには(おそらく非常に高速な)サブクエリが必要なため、最後のXよりも日付からすべてのログアイテムを選択する方が簡単です。



    1. SQLクエリからカウントを取得する

    2. MySQLdbを介して関数を作成する

    3. MariaDBでのINSTR()のしくみ

    4. 共通の列(A、B)と(A、C)を持つ2つのクエリを1つの(A、B、C)に変換するにはどうすればよいですか?