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

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

新規登録して質問してみよう
ただいま回答率
85.37%
GROUP BY

GROUP BYとはSQL文のひとつで、SELECT文において特定の列の値が等しい行ごとに表をグループ化します。

MySQL

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

Q&A

4回答

918閲覧

MySQLのGROUP BYとDISTINCTについて質問があります。

s_yoshi

総合スコア30

GROUP BY

GROUP BYとはSQL文のひとつで、SELECT文において特定の列の値が等しい行ごとに表をグループ化します。

MySQL

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

0グッド

0クリップ

投稿2023/09/11 21:03

テーブルA

CREATE table table_a
(
YYYYMM CHAR(6) NOT NULL,
CD1 CHAR(6) NOT NULL,
CD2 CHAR(2) NOT NULL,
CD3 CHAR(5) NOT NULL,
CD4 CHAR(2) NOT NULL,
CD5 CHAR(3) NOT NULL,
MAX1 CHAR(5) NOT NULL ,
MIN1 CHAR(5) NOT NULL,
CD6 CHAR (3) NOT NULL,
PRIMARY KEY (YYYYMM, CD1, CD2)
);

table_aには約3000万件のレコードがあります。
実行環境はAccess2016とOracleになっておりました。
これをAccess2016とMySQLで実現することになりました。
CD3,CD4,CD5をキーにしてMAX,MIN,COUNTの集合関数を使用します。
しかし、処理速度がOracleでは数分でしたがMySQLに変更すると処理時間が大幅に増え数十分から
1時間以上かかるようになりました。SQLについてはOracleとMySQLは同じ内容です。

今までのSQL
SELECT
CD3
, CD4
, CD5
, MAX(MAX1)
, MIN(MIN1)
, COUNT(CD6)
FROM table_a
GROUP BY
CD3
, CD4
, CD5
で実現定義してしておりました。

これをMySQLでは例として
SELECT
CD3
, CD4
, CD5
, MAX(MAX1)
, MIN(MIN1)
, COUNT(CD6)
FROM
(
SELECT DISTINCT
CD3
, CD4
, CD5
FROM table_a
) a
GROUP BY
CD3
, CD4
, CD5
イメージ的には、まずCD3,CD4,CD5で重複を除外しその結果からグルーピングして集合関数を
利用すればスピードアップが図れると思っておりますが、上記のSQLでは文法エラーになります。
この文法では文法エラーになって当然です。
とにかく処理時間を短縮する手法として皆様のお知恵をお借りしたいと思っております。
ご教示のほどよろしくお願いいたします。

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

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

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

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

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

sazi

2023/09/12 04:12 編集

そのSQLはAccessでのリンクテーブルに対してのAccessのクエリーですか? また質問では一つのテーブルですけど、実際には幾つものテーブルを使用しているというような事は無いですか?
pecmm

2023/09/12 10:48

回答返信から、oracle,mysqlどちらも適切にインデックスが使用されている前提とします。 joinもwhere相当も無いシンプルなクエリで、処理時間に10倍?くらいの差が出るとなると、他の原因を疑いたくなります たとえばmysqlは検証環境へ仮導入みたいな状況で、サーバのHW性能差が大きい…等はないですか?
guest

回答4

0

oracleで作業すればよいのでは?

追記:何故かスコア剥奪されたのだが。意味が分からない。テラテイルよ、スコアを返しなさい。
何故数分で作業出来る環境が既にあるのにSQLに変えて作業時間を増やすのか分からない。

投稿2023/09/12 00:08

編集2023/09/12 00:20
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

s_yoshi

2023/09/12 05:42

早速のご回答ありがとうございます。 現在Oracleで構築しておりますシステムが今回、顧客要望によりMySQLに変更せざることになりました。 よってどうしてもMySQLで実現しなくてはなりません。 このことを踏まえてよい案がありましたらご教示お願いいたします。
ikedas

2023/09/13 03:43

@EA_Maker2023さん 「SQLに変えて」って、……Oracle DatabaseもSQLデータベースなんですが。 @logres_Fanさん 質問の要件を無視している回答にグッドを繰り返し送る意図は何でしょうか。
guest

0

適切なインデックスを貼れば高速化は可能だと思います
MySQLの例としてあげているSQLは明らかにおかしいので実行できません

テスト

SQL

1CREATE table table_a 2( 3ID int primary key auto_increment, 4YYYYMM CHAR(6) NOT NULL, 5CD1 CHAR(6) NOT NULL, 6CD2 CHAR(2) NOT NULL, 7CD3 CHAR(5) NOT NULL, 8CD4 CHAR(2) NOT NULL, 9CD5 CHAR(3) NOT NULL, 10MAX1 CHAR(5) NOT NULL , 11MIN1 CHAR(5) NOT NULL, 12CD6 CHAR (3) NOT NULL, 13unique(YYYYMM, CD1, CD2), 14index(CD3,CD4,CD5,MAX1,MIN1,CD6) 15); 16 17insert into table_a(YYYYMM,CD1,CD2,CD3,CD4,CD5,MAX1,MIN1,CD6) values 18('202309','000001','01','30001','41','501','99001','90001','601'), 19('202309','000001','02','30001','41','501','99002','90001','601'), 20('202309','000001','03','30001','42','501','99003','90001','601'), 21('202309','000002','01','30001','41','501','99003','90001','601'), 22('202309','000002','02','30001','42','501','99002','90001','601');

explainで確認

SQL

1EXPLAIN SELECT 2CD3 3,CD4 4,CD5 5,MAX(MAX1) 6,MIN(MIN1) 7,COUNT(CD6) 8FROM table_a 9GROUP BY 10CD3 11,CD4 12,CD5

※結果

idselect_typetablepartitionstypepossible_keyskeykey_lenrefrowsfilteredExtra
1SIMPLEtable_aNULLindexCD3CD392NULL5100.00Using index

投稿2023/09/12 00:32

編集2023/09/12 07:21
yambejp

総合スコア116468

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

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

s_yoshi

2023/09/12 05:53

CD3,CD4,CD5の順番でインデックスを1つ定義してみました。しかし3000万件という膨大なデータ量では これといった改善が見られませんでした(ほぼインデックスを定義する前) 例に挙げたSQLはエラーで機能しないことは存じております。 これといった改善点が見いだせなれないのが現状です。 何とかお知恵を拝借できないでしょうか。ご教示のほどよろしくお願いいたします。
yambejp

2023/09/12 06:11

「今までのSQL」文からわざわざ「MySQLでは例」として非効率なサブクエリに書き換えているのはなにか意図があるのでしょうか?
ikedas

2023/09/12 06:32

多分話が逆で、遅いからサブクエリに書き換えれば (DISTINCTで処理するレコード数を減らせば) 改善しないかなー、というアイディアだと思います。
ikedas

2023/09/12 07:47 編集

@s_yoshi さん MAX1, MIN1, CD6にもインデックスをつけてはどうですか。集約関数ではNULLの行を無視する (「COUNT(*)」は例外で、単に全レコード数を返す) ので、インデックスがないと全ての行の実データを読んで実際にNULLでないことを確かめてしまいます。インデックスがあれば実データを読まないのですぐに終わります。 [追記] yambejpさんが追記された例ではレコード数が少ないため、インデックスなしで実データを全部読んでもそんなに遅くなっていませんが、同じことを3000万行のデータでやれば遅くなると思われます。
guest

0

結論を先に述べると、ボトルネックはMySQLとは考えにくく、AccessとMySQLの間のネットワーク部分か、Accessそのものがボトルネックだと考えられます。


そのへんで動いてたMariaDBで検証しました。

まず、ランダムデータで1 000 000行用意しました。

MariaDB [test]> SELECT COUNT(*) FROM table_a; +----------+ | COUNT(*) | +----------+ | 1000000 | +----------+ 1 row in set (0.86 sec) MariaDB [test]> SELECT * FROM table_a LIMIT 10; +--------+--------+-----+-------+-----+-----+-------+-------+-----+ | YYYYMM | CD1 | CD2 | CD3 | CD4 | CD5 | MAX1 | MIN1 | CD6 | +--------+--------+-----+-------+-----+-----+-------+-------+-----+ | 199001 | AAIYUH | BI | GJNNW | AN | JKQ | QDNPO | WQCBO | HLG | | 199001 | AAMYRC | OB | PIBAU | LH | XFH | HIPCE | WPKQB | FQG | | 199001 | AARQNL | JM | TBQDD | HQ | UDL | CKJAP | IKULH | DJL | | 199001 | AASJFC | MD | OFMPT | FN | HNP | NUCCR | UHGID | LOA | | 199001 | AAVASX | FL | HSPXF | SL | VBX | IAYAB | OGLFN | KUG | | 199001 | AAVQKI | UE | YCKRK | JB | ABM | CFEVY | HUWAF | XYG | | 199001 | ABEMMO | VP | EFNDL | YO | FSR | ONQKA | EBSBW | RLU | | 199001 | ABHXRO | EK | CFYUA | LR | NXS | LCRPQ | EAAXD | KKS | | 199001 | ABJSDJ | AE | FAMNW | UY | DPJ | BERQJ | XINPH | HYJ | | 199001 | ABQVNS | RN | SODEC | EL | JBM | AFIVJ | VBSJN | RPD | +--------+--------+-----+-------+-----+-----+-------+-------+-----+ 10 rows in set (0.01 sec)

実行計画を見ると、使えるインデックスがありません。

MariaDB [test]> EXPLAIN -> SELECT -> CD3 -> , CD4 -> , CD5 -> , MAX(MAX1) -> , MIN(MIN1) -> , COUNT(CD6) -> FROM table_a -> GROUP BY -> CD3 -> , CD4 -> , CD5; +------+-------------+---------+------+---------------+------+---------+------+--------+---------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+-------------+---------+------+---------------+------+---------+------+--------+---------------------------------+ | 1 | SIMPLE | table_a | ALL | NULL | NULL | NULL | NULL | 885048 | Using temporary; Using filesort | +------+-------------+---------+------+---------------+------+---------+------+--------+---------------------------------+ 1 row in set (0.01 sec)

実際、実行にそこそこの時間がかかります。とはいえそれほど極端にはかかりませんが。

MariaDB [test]> SELECT CD3 , CD4 , CD5 , MAX(MAX1) , MIN(MIN1) , COUNT(CD6) FROM table_a GROUP BY CD3 , CD4 , CD5 LIMIT 1; +-------+-----+-----+-----------+-----------+------------+ | CD3 | CD4 | CD5 | MAX(MAX1) | MIN(MIN1) | COUNT(CD6) | +-------+-----+-----+-----------+-----------+------------+ | AAAAE | FL | UMY | JPFAI | NBYLF | 1 | +-------+-----+-----+-----------+-----------+------------+ 1 row in set (20.27 sec)

インデックスを追加してみました。実行計画によると、インデックスが使えるようになりそうです。

MariaDB [test]> ALTER TABLE table_a ADD INDEX (CD3, CD4, CD5); Query OK, 0 rows affected (13.98 sec) Records: 0 Duplicates: 0 Warnings: 0 MariaDB [test]> ANALYZE TABLE table_a; +--------------+---------+----------+----------+ | Table | Op | Msg_type | Msg_text | +--------------+---------+----------+----------+ | test.table_a | analyze | status | OK | +--------------+---------+----------+----------+ 1 row in set (0.16 sec) MariaDB [test]> EXPLAIN SELECT CD3 , CD4 , CD5 , MAX(MAX1) , MIN(MIN1) , COUNT(CD6) FROM table_a GROUP BY CD3 , CD4 , CD5; +------+-------------+---------+-------+---------------+------+---------+------+--------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+-------------+---------+-------+---------------+------+---------+------+--------+-------+ | 1 | SIMPLE | table_a | index | NULL | CD3 | 30 | NULL | 910704 | | +------+-------------+---------+-------+---------------+------+---------+------+--------+-------+ 1 row in set (0.00 sec)

実行すると激速になりました。インデックスは効いてます。

MariaDB [test]> SELECT CD3 , CD4 , CD5 , MAX(MAX1) , MIN(MIN1) , COUNT(CD6) FROM table_a GROUP BY CD3 , CD4 , CD5 LIMIT 1; +-------+-----+-----+-----------+-----------+------------+ | CD3 | CD4 | CD5 | MAX(MAX1) | MIN(MIN1) | COUNT(CD6) | +-------+-----+-----+-----------+-----------+------------+ | AAAAE | FL | UMY | JPFAI | NBYLF | 1 | +-------+-----+-----+-----------+-----------+------------+ 1 row in set (0.05 sec) MariaDB [test]>

というわけで、MySQL自体は、インデックスがなくても質問者さんの経験したほど時間がかかるかどうかは疑問です。適切なインデックスをつければまったく問題ないでしょう。

一方、今回のテストでは完全にランダムなデータを用いたため、出力される行数はほぼテーブルの行数と同じでした。実際の環境ではこれほどではないにせよ、かなり出力行数が多くなると考えられます。つまり処理すべき出力量が多いことが問題の可能性があります。

結論として、ボトルネックはMySQLとは考えにくく、AccessとMySQLの間のネットワーク部分か、Accessそのものがボトルネックだと考えられます。

投稿2023/09/14 07:42

ikedas

総合スコア4443

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

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

0

#質問にコメントしてますが、返信が無いのでこちらに。
Accsesはどのように関係しますか?
SQLがAccsesのクエリーの話なら、パススルークエリーにする事をお薦めします。

追記

Accessのパススルークエリで実行しております。

質問のSQLは質問の為に改編していませんか? 
テーブル名やカラム名程度であれば問題ありませんが、SQLの構造を改編している場合は、SQLチューニングに関する質問に於いては致命的ですので。

上記該当しない場合は、以下の様な事も考えられます。
・oracleとMySQLそれぞれのSQLで参照している項目が同じで、データ件数も同等という事であれば、インデックスの定義内容が同じかどうか。

・oracleとMySQLでの環境との相違もレスポンスに関係します。
[メモリの割当] MySQLへの割り当てに不足が生じていないか
[環境] CPU/メモリ/ストレージ/ネットワーク等スペックは同等か
※上記が該当するなら、SQLチューニングに余地は無いと思います。
ネットワークに関しては、MySQLサーバー上で質問のSQLを実行しレスポンスを確認する事で、切り分けできます。

投稿2023/09/12 13:17

編集2023/09/13 05:10
sazi

総合スコア25300

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

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

s_yoshi

2023/09/12 23:46

ご回答ありがとうございます。 Accessのパススルークエリで実行しております。タイムアウトを10分に設定しておりますが この10分が限界と考えております。 どうしても良い案が見つからず焦っております。妙案がございましたらご教示お願いいたします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問