質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

データベース

データベースとは、データの集合体を指します。また、そのデータの集合体の共用を可能にするシステムの意味を含めます

Q&A

解決済

3回答

41374閲覧

多数のクエリをUNION ALLした場合のコストについて

milktea

総合スコア116

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

データベース

データベースとは、データの集合体を指します。また、そのデータの集合体の共用を可能にするシステムの意味を含めます

0グッド

0クリップ

投稿2016/11/08 03:05

そこそこ重いクエリを数百ほどUNION ALLした場合、メモリの使用量などはどのようになるのでしょうか。
1つのSQLを順に実行していった場合と近い処理になるのか、全てを同時に実行したような処理になるのか。
ひとまず結論がわかると助かりますが、これを確認する方法についても教えていただきたいです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2016/11/08 07:02

RDBMS名を指定してもらえれば、より的確なアドバイスが得られることでしょう。
guest

回答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

KiyoshiMotoki

総合スコア4791

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

milktea

2016/11/11 09:09

MySQLの場合は、1つのSQL文+一時テーブル分のメモリ消費、という形になるのですね。特殊な事情があり、1つのSQL文で全てのデータを取得したいと思っているので、UNION ALLを使って結合することにします。勉強になるご回答ありがとうございました。
guest

0

メモリは増やせば良いけど、それよりSELECT文を多数発行することの負荷が大きいです。
WHEREを工夫してSELECT文の発行をなるべく少なく済ませることを考えます。
その前に UNION ALL と書くべきところを UNION で書いて無駄な負荷をかけて平気なプログラマが多過ぎです。

投稿2016/11/08 03:16

Orlofsky

総合スコア16415

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

milktea

2016/11/22 07:06 編集

費用や権限の問題によりスペックを変更することができないのです。 重いクエリをUNION ALLで多数結合した場合、メモリを大量に消費してしまうのでしょうか(DBエンジンによって異なるかもしれませんが)。
Orlofsky

2016/11/08 03:51

どれだけ多くのメモリを消費するかは個々のSQLを調べないとわかりません。 http://www.oracle.com/technetwork/jp/ondemand/database/mysql/mysql-perftun-1484759-ja.pdf に載っているツールなどを参考にしてください。 UNION ALLは使わないで済むなら使わない方が良いです。 UNION ALLばかり気にされていますが、パフォーマンス・チューニングを効率的に行うにはパフォーマンスが悪い部分から改善するべきです。
guest

0

UNION ALLする前提ならなぜテーブルをわけているのでしょう?
場合によってはパーティショニングしておけばよいのではないでしょうか?

投稿2016/11/08 03:39

yambejp

総合スコア114767

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

milktea

2016/11/08 03:44

サイト上の様々な更新を日毎のレポートのように出力したいと考えています。
milktea

2016/11/08 09:46

同じテーブルであればGROUP BYで済みますが、例えば登録アクションや購入アクションなど全く異なるデータについてのサマリーを1つのクエリで取得したいのです。
yambejp

2016/11/08 09:50

テンポラリテーブルをつくって流し込めばよいのでは?
Orlofsky

2016/11/08 09:54

UNION ALL をいくつ使うつもりでしょうか? 日毎に登録アクションや購入アクションを並べたいとか、上記に書いたようにテーブルやそのデータと出力結果を提示していただけないと適切なコメントは難しいです。
Panzer_vor

2016/11/08 11:09

横やり失礼します。 とりあえず下記に思いつくことを並べてみた。 1.CASE式で事足りるならCASE式 2.データ量によるパフォーマンスに懸念があるならパーティションの導入 3.集計パターンが煩雑ならば中間結果をテンポラリテーブル化 4.UNION ALLでいくとして、共通部分が多い、かつ事前にある程度データを絞れるなら共通テーブル式(※MySQLは未サポート) どの程度複雑なことをやりたいのかわからないので何とも言えないですが、 複雑ならばテンポラリテーブルやらマテリアライズドビューを導入した方がパフォーマンスは望めると思います。
Panzer_vor

2016/11/08 11:19

おっとメモリ節約って所を見落としてた。 共通テーブル式はオンメモリとなるのでメモリ節約から見るとダメですね。 要件次第ですが、 リアルタイム性が低くてよいあれば、 サマリテーブルを追加して夜間バッチなり何なりで負荷の少ない時間帯で集計データ作成するのが一番楽ですね。 ちなみにメモリについては正確には分かりませんが、 UNION ALLでSELECT句を繋げる量があまりにも多いと、 単発で1つずつ実行するより時間を食う可能性は高いですよ。 DBMSにもよるのでしょうが、途端に全く結果が返ってこなくなるってこともありますし。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問