nodejs
アプリケーションのORMとして sequelize を使用しています。
シナリオはで、Poll
とそのOptions
を挿入してオブジェクトを取得する必要があります。
アプローチ1:
1-Poll
を挿入:
INSERT INTO `polls` (`id`,`start_at`,`expire_at`,`options_count`) VALUES (DEFAULT,1487945658,1487945965,3);
2-挿入Options
(一括挿入):
INSERT INTO `poll_options` (`id`,`poll_id`,`text`) VALUES (NULL,{id},'red'),(NULL,{id},'green'),(NULL,{id},'blue');
3-Options
を選択します(一括挿入によりid
が挿入されませんOption
が得られないため、選択する必要があります):
SELECT `id`, `poll_id`, `text` FROM `poll_options` WHERE `poll_id` = {id};
アプローチ2:
1-挿入Poll
2-Option
を1つずつ挿入します(この方法でid
も挿入できるので、最後に明示的なSELECTは必要ありません)
質問:
どちらのapproach
が良いでしょうか?
両方のテーブルで参照整合性が有効になっていて、innodbエンジンが使用されています。
performanceの場合、最初のアプローチの方が優れています。 これが理由です:
新しいデータがテーブルに挿入されるたびに、インデックスも更新され、物理的に並べ替えられます。 InnoDBの場合、インデックスファイルが更新されるだけでなく、データファイル自体も並べ替えられる可能性があり、主キーに基づいてclusteredになります。そのため、並べ替え/更新はコストのかかる操作であり、最小限に抑える必要があります。
一括挿入を実行すると、ステートメントが終了したときにインデックスが更新されます。つまり、すべての行を挿入した後。一方、個別に挿入すると、物理ファイルは挿入ごとに更新されます。
最初のアプローチの最後のselect
ステートメントのオーバーヘッドは無視できます。
あなたはORMを使用していますが、これは開発者にとってSQLの細かい詳細を隠蔽しますが、レコードと多数の詳細レコードを子テーブルに挿入するためのさまざまなアプローチに興味があるようです。
私は、意図を最も明確に伝え、より簡単に保守できるコードを選びます。私の意見では、これはおそらく2番目のオプションです。 (測定された)パフォーマンスが問題である場合にのみ、最適化を開始します。
しかし、それらは同じではありませんか?アプローチ1は、3つのIDの1つを取得します。アプローチ2では、3つのIDをそれぞれ取得します。
そして、なぜ_poll_options
_のid
が必要なのですか?
これのようにあなたが必要なすべてです:
_BEGIN;
INSERT INTO `polls` (`start_at`,`expire_at`,`options_count`)
VALUES (1487945658,1487945965,3);
-- note: no mention of polls.id, above.
{id} = LAST_INSERT_ID() -- however your language does this
INSERT INTO `poll_options` (`poll_id`,`text`)
VALUES
({id},'red'),
({id},'green'),
({id},'blue');
-- again, no mention of poll_options.id
COMMIT;
_
それでも、BEGIN
とCOMMIT
は実際には必要ありません。 (最悪の場合、polls
に行を格納してから、_poll_options
_に行を格納できないことがあります。
パフォーマンス:
LAST_INSERT_ID()
の取得は、どのSELECT
よりも高速です。