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

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

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

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

JOIN

これはSQL文のJOINに関するタグです。リレーショナルデータベースシステムの二つ以上のテーブルを結合する際に、この構文が利用されます。

Q&A

1回答

16470閲覧

MySQLのjoin結合でINDEXを有効にさせたい

ochiaishiro

総合スコア28

MySQL

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

JOIN

これはSQL文のJOINに関するタグです。リレーショナルデータベースシステムの二つ以上のテーブルを結合する際に、この構文が利用されます。

0グッド

0クリップ

投稿2019/03/29 08:14

前提・実現したいこと

MySQL8.0を利用し、下記のテーブルPolyがあります。なお、そのレコード数は約24万です。

MySQL

1# Input table 2CREATE TABLE IF NOT EXISTS Poly ( 3 id INTEGER AUTO_INCREMENT, 4 prop int(11),#各ポリゴンの属性 5 geom POLYGON NOT NULL, 6 PRIMARY KEY (id), 7 SPATIAL KEY `geom`(geom)); 8# Output table 9CREATE TABLE IF NOT EXISTS child_parent ( 10 child INTEGER NOT NULL, 11 parent INTEGER NOT NULL, 12 geom_c POLYGON NOT NULL,# child のgeom 13 PRIMARY KEY (child ,parent), 14 SPATIAL KEY `geom_c`(geom_c));

実現したいことは、このテーブルから、ポリゴン属性が互いに同じで且つ隣接しているポリゴンの組み合わせを新たなテーブルchild_parentとして出力することです。
最終的な目的は、ポリゴン属性が互いに同じで且つ隣接しているポリゴンを一つのポリゴンにまとめたテーブルを作ることですが、まず、この段階で時間がかかることを解決したいのです。

発生している問題・エラーメッセージ

問題は、レコード数が大きいので、実行時間が多大(40時間でlost connection)にかかることです。
希望は、数時間で終わることを期待しています。

該当のソースコード

最初に実行したSQLです。(40時間でlost connection)
なお、TEMPORARYテーブルは一つのSQLの中で、2回以上は呼び出すことができないというので、Polyとまったく同じものを二つ(Poly_a、Poly_b)用意し、その二つをjoinしています。

MySQL

1INSERT INTO child_parent(child,parent,geom_c) 2select w.id,w.parent,w.geom from 3(SELECT 4 a.id as id, 5 b.id as parent, 6 a.geom as geom 7from Poly_a as a 8join Poly_b as b 9WHERE 10 a.id > b.id and # 自分同士と同じ組み合わせは重複するので不要 11 a.prop = b.prop and # ポリゴンの属性が同じものだけ 12 ST_GeometryType(ST_UNION(a.geom,b.geom)) = 'POLYGON' # 隣接するものだけ 13) as w 14group by w.id;#最終的な目的を考えて、w.idでまとめる。 15

試したこと

時間がかかるので、explainでキーがどのように有効になっているかを以下の通り、確認しました。

MySQL

1explain 2select w.id,w.parent,w.geom from 3(SELECT 4 a.id as id, 5 b.id as parent, 6 a.geom as geom 7from Poly_a as a 8join Poly_b as b 9WHERE 10 a.id > b.id and 11 a.prop = b.prop and 12 ST_GeometryType(ST_UNION(a.geom,b.geom)) = 'POLYGON' 13) as w 14group by w.id; 15 16| id| select_type| table| partitions| type| possible_keys| key| key_len| ref| rows| filtered| Extra| 17|'1'| 'SIMPLE'| 'b'| NULL| 'ALL'| 'PRIMARY'| NULL| NULL| NULL| '248008'| '100.00'| 'Using temporary'| 18|'1'| 'SIMPLE'| 'a'| NULL| 'ALL'| 'PRIMARY,geom_a'| NULL| NULL| NULL| '248097'| '0.33'| 'Using where; Using join buffer (Block Nested Loop)'| 19

結果を見ると、テーブルaのpossible_keysは'PRIMARY,geom_a'となっており、PKとSpatialkeyとが含まれています。しかし、テーブルbのpossible_keysにはが含まれていません。filteredも100になっていて、全てが対象になっている模様です。
なお、テーブルaとテーブルbには、それぞれSPATIAL KEYgeom_a,geom_bを設定しています。

そこで、USE INDEX (PRIMARY,geom_a)、USE INDEX (PRIMARY,geom_b)を使ってみましたが、結果は同じでした。
下記のように、FORCE INDEX()を使ったところ、少し結果が異なりましたが、恐らく時間短縮は見込めないと思われます。

MySQL

1explain 2select w.id,w.parent,w.geom from 3(SELECT 4 a.id as id, 5 b.id as parent, 6 a.geom as geom 7from Poly_a as a FORCE INDEX (PRIMARY,geom_a) 8join Poly_b as b FORCE INDEX (PRIMARY,geom_b) 9WHERE 10 a.id > b.id and 11 a.prop = b.prop and 12 ST_GeometryType(ST_UNION(a.geom,b.geom)) = 'POLYGON' 13) as w 14group by w.id; 15 16| id| select_type| table| partitions| type| possible_keys| key| key_len| ref| rows| filtered| Extra| 17|'1'| 'SIMPLE'| 'a'| NULL| 'ALL'| 'PRIMARY,geom_a'| 'PRIMARY'|4| NULL| '248097'| '100.00'| NULL| 18|'1'| 'SIMPLE'| 'b'| NULL| 'ALL'| 'PRIMARY'| NULL| NULL| NULL| '248008'| '0.33'| 'Range checked for each record (index map: 0x1)'| 19

補足情報

MySQLのバージョン:GPL 8.0.12
OS:Windows 7 Professional 64bit
RAM:8.0GB

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

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

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

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

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

yambejp

2019/03/29 08:23

> TEMPORARYテーブルは一つのSQLの中で、2回以上は呼び出すことができない Polyは普通のテーブルのように見えますがテンポラリなのですか? わざわざテンポラリをつくることなく自己結合してはいけないのでしょうか?
ochiaishiro

2019/03/29 08:44 編集

ありがとうございます。 実際は、Stored Procedureの中で処理することを考えています。この処理は、全体の処理の一部のため、処理中に他のセッションからは見えない、また、終了したら消えるTEMPORARYとしました。ただ、質問に当たっては、普通のテーブルとして書きました。 問題は、TEMPORARYかどうかではなく、効率的なjoinを行えないかということです。
yambejp

2019/03/29 08:47

Polyを各テンポラリに流し込むのですね? テンポラリを作成するときにきちんとテンポラリ自体にも Polyと同等のインデックスは貼ってありますか?
ochiaishiro

2019/03/29 08:58

はい、同じようにPKとインデックスを作成しています。
guest

回答1

0

式インデックスを適用されてみてはどうでしょう。
MySQL 8.0.13の式インデックス

投稿2019/03/29 08:34

編集2019/03/29 08:35
sazi

総合スコア25300

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

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

ochiaishiro

2019/03/29 08:56

面白そうですね。試してみます。ありがとうございました。
sazi

2019/03/29 09:14

よく見ると結合した別テーブルの項目使用してるので、使えないですね。 後検討するとしたら再帰ですかね
ochiaishiro

2019/04/01 03:48

再帰クエリー(CTE)は、この後の処理で使用しています。 この段階の結果として隣接関係を取得し、それを親子関係とみなして、CTEでまとめています。
ochiaishiro

2019/04/01 03:51

joinの結果が(n**2)/2とnが大きくなると指数的に大きくなるので、全体を適当な数になるまで分割するしかないですかね? 他に解決策がなければ、分割して処理します。
ochiaishiro

2019/04/03 05:57

はい、この後の処理でRECURSIVE付の再帰を行っています。 前処理のこの段階では、CTEとその中のサブクエリー部でのJOINする親子関係の情報をどうしたらいいか、理解できないでいます。 そこで、さらに前処理で、元のテーブルを「ポリゴン属性が互いに同じ」でgroupbyして、各グループのカウントを求め、さらにカウントの積算を求めるのにRECURSIVE付の再帰を利用し、適当なサイズごとに元のテーブルを分割抽出することを考えています。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

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

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

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問