
そこそこ重いクエリを数百ほどUNION ALL
した場合、メモリの使用量などはどのようになるのでしょうか。
1つのSQLを順に実行していった場合と近い処理になるのか、全てを同時に実行したような処理になるのか。
ひとまず結論がわかると助かりますが、これを確認する方法についても教えていただきたいです。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。


回答3件
0
ベストアンサー
MySQLに限って回答させていただくと、、
UNION または UNION ALL を使用した場合、SQLを1つずつ順に実行した場合と比べて
一時的に使用するメモリの量(※)は増えるはずです。
※「のべ」の使用量については、分かりません。
なぜなら、MySQL は UNION 句が含まれるクエリを実行する際に内部一時テーブルを作成するからです。
https://dev.mysql.com/doc/refman/5.6/ja/internal-temporary-tables.html
一時テーブルは、次のような条件で作成される可能性があります。
・ UNION クエリーが一時テーブルを使用します。
上の引用句では「可能性があります」という記載ですが、UNION 句に関しては必ず内部一時テーブルが作成されるようです。
手元の環境(MySQL 5.7)で確認した限りでは、2つの空のテーブルを UNION しただけでもCreated_tmp_tablesステータス変数が増加したからです。
sql
1mysql> CREATE TABLE table_1 (id int); 2Query OK, 0 rows affected (0.04 sec) 3 4mysql> CREATE TABLE table_2 (id int); 5Query OK, 0 rows affected (0.04 sec) 6 7mysql> SHOW STATUS LIKE 'Created_tmp_tables'; 8+--------------------+-------+ 9| Variable_name | Value | 10+--------------------+-------+ 11| Created_tmp_tables | 16 | 12+--------------------+-------+ 131 row in set (0.00 sec) 14 15mysql> SELECT * FROM table_1; 16Empty set (0.00 sec) 17 18mysql> SELECT * FROM table_2; 19Empty set (0.00 sec) 20 21mysql> SHOW STATUS LIKE 'Created_tmp_tables'; # 個々に SELECT した場合は一時テーブルは作成されない 22+--------------------+-------+ 23| Variable_name | Value | 24+--------------------+-------+ 25| Created_tmp_tables | 16 | 26+--------------------+-------+ 271 row in set (0.00 sec) 28 29mysql> SELECT * FROM table_1 UNION ALL SELECT * FROM table_2; 30Empty set (0.00 sec) 31 32mysql> SHOW STATUS LIKE 'Created_tmp_tables'; 33+--------------------+-------+ 34| Variable_name | Value | 35+--------------------+-------+ 36| Created_tmp_tables | 17 | 37+--------------------+-------+ 381 row in set (0.00 sec)
おそらく、MySQL の内部では
UNION 句によって結合される全てのデータを内部一時テーブルに格納してから、 その一時テーブルのデータをクライアントに返却する
という動作が行なわれていると思われます。
さらに言うと、この内部一時テーブルは最初はインメモリとして作成されますが、テーブルのサイズが一定以上になるとディスク上に書き出されるようです。
上と同じリンク
サーバーは最初にインメモリーテーブルとして内部で一時テーブルを作成し、それが大きくなりすぎた場合に、それをディスク上テーブルに変換することがあります。
一般的に、ディスクの読み書き速度はメモリ上のそれと比べて遅いので、UNION 句はクエリの実行速度も悪化する可能性があると言えます。
単にリソースの節約だけが目的であれば、クエリを1つずつ実行する方が良いでしょう。
もし、その場合に
「一貫したデータが取得できなくなる」
ことも懸念されているのでしたら、START TRANSACTION WITH CONSISTENT SNAPSHOT
クエリが使用できないか、検討してみてはいかがでしょうか?
https://dev.mysql.com/doc/refman/5.6/ja/commit.html
WITH CONSISTENT SNAPSHOT 修飾子は、この機能に対応しているストレージエンジンでの一貫性読み取りを開始します。
もしくは、Panzer_for様のコメントのようにサマリテーブルを作成する、などの対応のほうが、多数のクエリを UNION するより良いと思います。
投稿2016/11/08 15:23
総合スコア4791
0
メモリは増やせば良いけど、それよりSELECT文を多数発行することの負荷が大きいです。
WHEREを工夫してSELECT文の発行をなるべく少なく済ませることを考えます。
その前に UNION ALL と書くべきところを UNION で書いて無駄な負荷をかけて平気なプログラマが多過ぎです。
投稿2016/11/08 03:16
総合スコア16417
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
UNION ALLする前提ならなぜテーブルをわけているのでしょう?
場合によってはパーティショニングしておけばよいのではないでしょうか?
投稿2016/11/08 03:39
総合スコア117436
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/11/08 06:40
2016/11/08 09:54
2016/11/08 11:09
2016/11/08 11:19

あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。