3

Joomlaのようないくつかの主要なシステムは、タグをコンマ区切りのテキストとしてメインの記事データベースに保存しますが、記事、タグ、タグの関係として3つのテーブルの正規化されたシステムが推奨されます(Wordpressのような他のシステムが使用するように)。構造と読書についてはたくさんの議論と質問があります。しかし、3つのテーブルに挿入する必要があるため、最適なINSERTコマンドを見つけることができませんでした。1回のSQL実行でこのプロセスをすばやく実行するにはどうすればよいですか?または、最初に記事を挿入し、次に各タグを挿入し、最後に関係を記述する必要がありますか?

もう1つの質問は、タグの一意性についてです。このシステムの主な利点は、各用語を1回だけ保存する必要があることです(その後、対応する記事に接続します)。重複を避けるためにmysqlUNIQUEを使用することは実用的ですか?または(どこかで読んだように)タグのリスト全体を配列として読み取って、タグIDをキャッチし、用語の保存を回避するための重複を見つける必要がありますか?

プロセス全体を3つの個別のステップとして実行しますか?

  1. 記事を挿入
  2. UNIQUEを使用してタグを挿入しますが、それらの関係は関係ありません
  3. 各タグIDを見つけて、記事IDとの関係を作成します

私は正しいですか?私が尋ねた理由は、人々がタグを配列としてキャッチして比較するのを見たからです。私にとっては非常に遅く、特にUPDATEの場合はパフォーマンスが低下します。

4

4 に答える 4

4

一度に挿入できるのは1つのテーブルのみです。

1つの解決策はトリガーを使用することであり、もう1つはトランザクションを使用することです。
前者は任意のエンジンで使用でき、後者はInnoDBまたは同様のエンジンを必要とします。

必ずUNIQUEフィールドにインデックスを付けてくださいtag.name

1-トランザクションの使用

START TRANSACTION;

INSERT IGNORE INTO tag (name) VALUES ('$example1', '$example2');
INSERT INTO article (title, body) VALUES ('$title','$body');
SET @article_id = LAST_INSERT_ID();
INSERT INTO tag_link (tag_id, article_id) 
  SELECT t.id, @article_id FROM tag t WHERE t.name IN ('$example1','$example2');

COMMIT;

2-ブラックホールテーブルでトリガーを使用する

blackhole次のフィールドを使用して タイプのテーブルを作成します。

title: varchar(255)
body: text
tag1: varchar(50) DEFAULT NULL
tag2: varchar(50) DEFAULT NULL
...
add as many tags as you want.

AFTER INSERTブラックホールテーブルにトリガーを追加して、実際のストレージを実行します。

DELIMITER $$

CREATE TRIGGER ai_bh_newacticle_each AFTER INSERT ON bh_newacticle FOR EACH ROW
BEGIN
  INSERT IGNORE INTO tag (name) VALUES (new.tag1, new.tag2,...,new.tag25);
  INSERT INTO article (title, body) VALUES (new.title,new.body);
  SET @article_id = LAST_INSERT_ID();
  INSERT INTO tag_link (tag_id, article_id) 
    SELECT t.id, @article_id FROM tag t 
    WHERE t.name IN (new.tag1, new.tag2,...,new.tag25);
END$$

DELIMITER ;

DELIMITER $$

これで、タグ付きの記事を1つのステートメントに挿入できます。

INSERT INTO bh_newarticle (title, body, tag1, tag2, tag3) 
  VALUES ('$title','$body','$tag1','$tag2','$tag3');

質問に戻る

私は正しいですか?私が尋ねた理由は、人々がタグを配列としてキャッチして比較するのを見たからです。私にとっては非常に遅く、特にUPDATEの場合はパフォーマンスが低下します。

タグは、数が限られている場合にのみ役立ちます。タグの検索に(一意の)インデックスをtag.name付けると、10.000個のタグがあっても非常に高速になります。これは、完全に一致するものを探しているためです。そして、本当に急いでいる場合は、いつでもタグテーブルをフィールド上にあるmemoryテーブルにすることができます。 ただし、タグ検索の速度の低下について心配する必要はないと思います。 hash indexname

記事ごとにあまり多くのタグを許可しないように注意してください。5は良いスタートのようです。10は多すぎます。

リンク
http://dev.mysql.com/doc/refman/5.0/en/create-trigger.htmlhttp://dev.mysql.com/doc/refman/5.0/en/blackhole-storage-engine.html
_

于 2011-09-20T15:16:54.923 に答える
1

1つのステートメントで3つのテーブルに挿入することはできませんが、1つのトランザクションで3つの挿入ステートメントを実行することはできます。

重複を避けたいので、タグ列を一意として宣言することに問題はありません。タグをテーブルに挿入する前に、タグが存在するかどうかをいつでも確認できます。タグを挿入するだけupsertです。

于 2011-09-20T15:12:08.883 に答える
1

単一のクエリを発行して各INSERTを実行します。「回避策」はなく、存在することさえ不可能です。したがって、3つのテーブルに対して3つの挿入があります。

一意のタグが必要な場合は、そうです。重複を避けるために、UNIQUE制約を使用することをお勧めします。

単純なINSERT IGNOREMySQL機能は、挿入する前にレコードが存在するかどうかを回避するのに役立つトリックを実行する必要があります。

于 2011-09-20T15:14:54.397 に答える
0

DBMSの機能に応じていくつかの可能性があります。つまり、トリガーの代わりにストアドプロシージャを使用して、1つのSQLステートメントで挿入できるようにすることができますが、3つすべてに挿入することもそれほど重要ではないため、価値がないと思います。 1つのトランザクションでテーブル...記事は保存されてもタグの保存に失敗しても悪くありません...しかし、必要に応じて、複雑なロジックが可能であり、サブプログラムを記述できるため、このタスクにはストアドプロシージャが最適です。プログラムですべてのSQLを実行し、必要に応じて1行で呼び出します...

タグフィールドのタグテーブルとフィールド(article_id、tag)のrelテーブルに一意のインデックスを作成できます。

于 2011-09-20T15:24:16.393 に答える