1

結合テーブルInfoによってエントリ数が少ないテーブルTagsにリンクされているArticlesのプライマリテーブルがあります。特定のタグへのリンクがないことに基づいて、行を削除するか、必要なエントリのみを使用して新しいテーブルを作成することにより、Articlesテーブルを分割したいと思います。数百万の記事があります。これどうやってするの?

すべての記事にタグが付いているわけではなく、多くのタグが付いている記事もあります。

例:

table Articles
  primary_key id
table Info
  foreign_key article_id
  foreign_key tag_id
table Tags
  primary_key id

すぐに一致する記事を分離するのは簡単だったので、それを実行してからNOT INステートメントを使用できると思いましたが、実行速度が非常に遅いため、終了するかどうかは不明です。私はこれらのコマンドでそれをしました:

INSERT INTO matched_articles SELECT * FROM articles a LEFT JOIN info i ON a.id = i.article_id WHERE i.tag_id = 5;
INSERT INTO unmatched_articles SELECT * FROM articles a WHERE a.id NOT IN (SELECT m.id FROM matched_articles m);

それが違いを生むなら、私はPostgresにいます。

4

3 に答える 3

1

最初のクエリは左結合ではなく内部結合である必要があることを除いて、クエリは問題ないように見えます。他のことを試したい場合は、次のことを検討してください。

INSERT INTO matched_articles 
SELECT * 
FROM articles a 
INNER JOIN info i ON a.id = i.article_id 
WHERE i.tag_id = 5;

INSERT INTO unmatched_articles 
SELECT * 
FROM articles a 
LEFT JOIN info i ON a.id = i.article_id AND a.id <> 5
WHERE a.id IS NULL

それは速いかもしれませんが、実際には、一度だけ実行する必要がある場合は、おそらく大丈夫です。

于 2010-03-20T18:17:12.000 に答える
1
INSERT INTO matched_articles 
SELECT * FROM articles a LEFT JOIN info i ON a.id = i.article_id WHERE i.tag_id = 5; 

INSERT INTO unmatched_articles 
SELECT * FROM articles a WHERE a.id NOT IN (SELECT m.id FROM matched_articles m); 

ここには多くの間違いがあり、どこから始めればよいのかわかりません。最初の挿入では、左結合は必要ありません。実際には、左結合はありません。そのはず

INSERT INTO matched_articles 
SELECT * FROM articles a INNER JOIN info i ON a.id = i.article_id WHERE i.tag_id = 5; 

もしあなたが左の参加を必要としていたなら、あなたは持っていただろう

INSERT INTO matched_articles 
SELECT * FROM articles a LEFT JOIN info i ON a.id = i.article_id AND i.tag_id = 5; 

左結合の右側からwhere句に何かを入れると(null値の検索以外)、その条件を満たす必要があるため、内部結合に変換します。したがって、右の表の一致は削除されます。

これで、2番目のステートメントは、左結合の特殊なケースで実行できますが、持っているものは機能します。

INSERT INTO matched_articles 
SELECT * FROM articles a 
LEFT JOIN info i ON a.id = i.article_id AND i.tag_id = 5
WHERE i.tag_id is null

これにより、articlesテーブルに一致するものを除いて、infoテーブルにあるすべてのレコードが得られます。

次に、挿入するフィールドを指定せずに挿入文を記述しないでください。また、特に結合がある場合は、select*を使用してselectステートメントを記述しないでください。これは一般的にずさんな、怠惰なコーディングであり、修正する必要があります。誰かが一方のテーブルの構造を変更したが、もう一方のテーブルの構造を変更しなかった場合はどうなりますか?この種のことはメンテナンスに不利であり、結合のあるselectステートメントの場合、列を2回返し(結合列)、サーバーとネットワークのリソースを浪費します。必要なものと必要なものだけを指定するのが面倒なのは、コーディングが不十分なだけです。したがって、習慣から抜け出し、本番コードに対して再度実行しないでください。

現在のスタメントが遅すぎる場合は、適切なインデックスで修正できる可能性もあります。idフィールドは両方のテーブルでインデックス付けされていますか?一方、数百万の記事がある場合は、挿入に時間がかかります。多くの場合、一度に50000のバッチでこれを行う方がよいでしょう(これに時間がかかりすぎる場合は、さらに少なくなります)。上位のXXXレコードを選択する挿入inaループを実行してから、影響を受ける行数がなくなるまでループします。

于 2010-03-20T18:21:51.850 に答える
1

Postgresに一時テーブルの概念があるかどうかはわかりません。
これを行う方法も次のとおりです。

CREATE Table #temp
AS SELECT A.ID, COUNT(i.*) AS Total
FROM Articles A
LEFT JOIN info i
ON A.id = i.Article_ID AND i.Tag_ID = 5
GROUP BY A.ID

INSERT INTO Matched_Articles
SELECT A.*
FROM Articles A INNER JOIN #temp t
ON A.ID = t.Article_ID AND T.Total = 0

DELETE FROM #Temp
WHERE Total = 0

INSERT INTO UnMatched_Articles
SELECT A.*
FROM Articles AINNER JOIN #temp t
ON A.ID = t.Article_ID

これを試すためにエディターを使用していないことに注意してください。
これが私がこれにどのように取り組むかについてのヒントをあなたに与えることを願っています。

于 2010-03-20T18:26:57.753 に答える