5

次の参加は、特定のステータスを持つユーザーのメッセージとともにユーザー情報を取得することになっています。

SELECT * FROM user, message WHERE message.user_id=user.id AND user.status=1

問題は、結果セット内の特定のユーザーに関するすべての行に、そのユーザーに関する同じデータ (ユーザー テーブルから取得されたフィールド) を繰り返す冗長な列が含まれており、メッセージ テーブルのフィールドのみに冗長でない情報が含まれていることです。このようなもの:

user.id  username email            message.id  subject
1        jane     jane@gmail.com   120         Notification 
1        jane     jane@gmail.com   122         Re:Hello 
1        jane     jane@gmail.com   125         Quotation
2        john     john@yahoo.com   127         Hi jane
2        john     john@yahoo.com   128         Fix thiss 
2        john     john@yahoo.com   129         Ok
3        jim      jim@msn.com      140         Re:Re:Quotation

ご覧のとおり、多くのデータは冗長であり、最初にユーザーを見つけてから、ループのような構造などでメッセージを処理したくありません。マイクロクエリを引き起こすループは、何としても避けるべきです。

UI で適切に処理されるプログラムの出力については心配していません。このクエリの結果を返すことによって生成されるネットワーク トラフィックは、そのユーザーに関連するすべての行で何らかの方法でユーザー データの繰り返しをなくすことができれば、おそらく大幅に削減できると思います

4

4 に答える 4

3

知っておくべきことがいくつかあります。

1 つ目は、デフォルトの SQL JOIN コンストラクトが本質的にセットの外積であり、WHERE 句によって制限されていることです。これは、乗法であることを意味します - 重複した結果が得られ、それを削除します。NULL フィールドの存在にも注意する必要があります。

2 つ目は、「DISTINCT」キーワードがあることです。選択範囲の列にこれをプレフィックスとして付けると、結果のその列の特定の値のインスタンスが最大で 1 つ得られます。したがって、クエリに従って、「SELECT DISTINCT user.id FROM」はサーバー側の冗長性を排除します。

3 つ目は、この問題を解決する正しい方法は、おそらく*演算子を使用しないことです。私は提案します:

SELECT user.id,username,email,subject FROM message m,user WHERE m.user_id=user.id AND user.status=1

これは単純で理解しやすい暗黙的な結合構文を使用しており、どのサーバーでも有効な SQL である必要があります。少なくとも、MySQL で動作することを保証できます。また、'message' テーブルを省略形として 'm' にエイリアスします。

ご想像のとおり、これにより SQL サーバーからデータベースへのトラフィックが減少します。

編集:「冗長な」電子メール情報を削除したい場合はできません.2つの異なるクエリを作成する必要があります. SQL の結果は表であり、すべての既知の値が入力された長方形でなければなりません。「同上」の記載はありません。

編集 2: 2 つのクエリを作成するだけで済みます。例えば:

SELECT subject FROM message WHERE message.id IN (SELECT user.id FROM user WHERE status=1)

これは、ネストされたクエリを含む 1 つのクエリであるため、実際には 2 つのデータベース ヒットを作成しています。ただし、プログラムによるループはありません。

于 2010-07-05T05:34:09.200 に答える
1

ストレートSQLクエリでは、それらを単一のクエリとして保持する場合はありません。これをプログラムで印刷する場合は、ユーザー ID で並べ替え、ユーザー ID が変更された場合にのみその情報を再印刷します。

于 2010-07-05T04:48:57.817 に答える
1

SQL 標準では、NATURAL JOIN を使用します。これは共通の列名で結合し、それらの共通名のコピーを 1 つだけ保持します。

実際には、'*' 簡略表記に頼るのではなく、必要な列を慎重にリストします。

于 2010-07-05T04:58:41.133 に答える
0

ストアドプロシージャを使用できると仮定すると、上記のクエリを実行するためのプロシージャを記述し、カーソルを使用して「冗長情報」のnullを格納し、次のようなものを取得できます。

user.id  username email            message.id  subject 
1        jane     jane@gmail.com   120         Notification  
null     null     null             122         Re:Hello  
null     null     null             125         Quotation 
2        john     john@yahoo.com   127         Hi jane 
null     null     null             128         Fix thiss  
null     null     null             129         Ok 
3        jim      jim@msn.com      140         Re:Re:Quotation

次に、この結果セットを一時テーブルに返します。ただし、これによりネットワークトラフィックが減少する可能性がありますが、処理のオーバーヘッドが追加されます。

もう1つの方法は、2つのクエリを実行することです。1つはユーザー情報を取得し、もう1つはリンクされたユーザーIDのみでメッセージ情報を取得し、アプリケーションサーバー側のコードを使用して「参加」します。何かのようなもの

SELECT DISTINCT user.* FROM user, message WHERE message.user_id=user.id AND user.status=1

SELECT user.id, message.* FROM user, message WHERE message.user_id=user.id AND user.status=1

これにより、データベースへのトリップが1回ではなく2回になり、ネットワークトラフィックが減少した場合でも、最終的には遅くなる可能性があります。

そして別の方法は、これら2つを次のような単一の結果セットにまとめることです。

SELECT user.* FROM user, message WHERE message.user_id=user.id AND user.status=1
UNION ALL
SELECT user.id, message.* FROM user, message WHERE message.user_id=user.id AND user.status=1

のようなものを取得するには

   user.id  username/message.id    email/subject 
    1        jane                   jane@gmail.com   
    2        john                   john@yahoo.com   
    3        jim                    jim@msn.com      
    1        120                    Notification           
    1        122                    Re:Hello           
    1        125                    Quotation          
    2        127                    Hi jane          
    2        128                    Fix thiss           
    2        129                    Ok          
    3        140                    Re:Re:Quotation

次に、アプリケーションサーバーロジックを使用して分離します。ネットワークトラフィックは減少しますが、アプリケーションサーバーの負荷が増加します/データベースサーバーの負荷がわずかに増加します。

ただし、保存されたネットワークトラフィックが、複雑さを増すだけの価値があることはめったにありません。

于 2010-07-05T05:59:47.923 に答える