
MySQLの抽出時間を短縮できないため困っております
productテーブル
product_id,test_id
86009,'10701,8545'
84334,'12610,9505,13326,9024,1020747,6787,3737,5266'
85078,'1001182,1002129,1003064'
84082,'24723,23417,1002357,1000683,1002258,1003501,25426'
85072,'1008167,1007194,1006309,5240,1009347,30212'
85071,'28079,1007881,1000733,1002367,27836,25141,29863'
86014,'23988,17802,26440,1005928,22668,28372,28135'
83762,'1010127,1010436,1011554,1013949,1014307'
test_masterテーブル
id,initial_kana
10701,'あ'
21122,'あ'
1002129,'あ'
1002357,'い'
2291,'い'
29863,'い'
23988,'う'
1010436,'え'
22299,'え'
上記の2つのテーブルがあります。
内容は下記のようになります。
productテーブルの
product_id:一意のID
test_id:test_masterテーブルの一意のID(test_master.id)のカンマ区切りで接続した文字列
実際のレコード数:86,688件
test_masterテーブルの
id:一意のID
initial_kana:全角一文字のみ
実際のレコード数:14,602件
【やりたいこと】
(1)test_masterテーブルのtest_master.initial_kanaカラムに対応する文字(例えば'あ')に対応するtest_master.idを取得する
(2)(1)で取得したtest_master.id群を元に、productテーブルのtest_idに
該当する(product.test_id文字列の中にtest_master.idが入っているもの)もののproduct.product_idを取得する
ということをしたいのです。
(3)例えば、test_master.initial_kana='あ'を取得したい場合、productテーブルのproduct.product_id=86009,85078が取得される
私の作ったSQLは下記のものになります
limitとoffsetに関しては、都合上消すことはできません。
・test_masterテーブルから、test_master.initial_kana='あ'のものを抽出
・productテーブルから、product.test_idがNULLでないものを抽出
・上記二つから、FIND_IN_SETで、test_master.idに該当するproduct.test_idの文字列の中から抽出
---------------------------------------------------------
selectp.product_id as product_id,
am.id as id
from (select id
from test_master
where initial_kana = 'あ' ) as am,
(select product_id,test_id
from product
where test_id is not null
) p
WHERE ( FIND_IN_SET(am.id, p.test_id)!=0 )
group by am.id
limit 20
offset 0
---------------------------------------------------------
このSQLを実行すると件数が多いためか
30秒ほど掛かってしまい実用に耐えられない状況です。
すみませんが、SQLに詳しい方がいらっしゃいましたら
ご教授をお願いできますでしょうか。
検索が5秒くらいまで短縮できれば万々歳なのですが…
よろしくお願いいたします
A 回答 (3件)
- 最新から表示
- 回答順に表示
No.3
- 回答日時:
test_masterテーブルの「initial_kana」にINDEXはありますか?
なかったら付けてください。
後、インラインビューの「where test_id is not null」の必要性
が分かりません。
「test_id」にINDEXがあり、しかも内容がほとんどNULLならば、
この段階で絞込むこともあるかもしれませんが、そうでないなら、
FIND_IN_SET関数の判定と二重チェックになると思います。
selectp.product_id as product_id, am.id as id
from test_master as am join product as p
on am.initial_kana = 'あ'
and FIND_IN_SET(am.id, p.test_id)<>0
group by am.id
limit 20
offset 0
で試してみてください。
No.2
- 回答日時:
なんだか、すごく、違和感を感じるSQL文です。
処理時間も、結構無駄っぽい気がする。
とりあえず、等価なSQL文を作ってみると、
select p.product_id as product_id,
am.id as id
from product p join test_master am on FIND_IN_SET(am.id, p.test_id)!=0
where am.initial_kana = 'あ'
group by am.id
limit 20
offset 0
もし、joinで、文句を言われるようなら、
select p.product_id as product_id,
am.id as id
from product p , test_master am
where am.initial_kana = 'あ' and FIND_IN_SET(am.id, p.test_id)!=0
group by am.id
limit 20
offset 0
productテーブルのtest_idが、nullではないという条件は、多分不要です。というのは、test_idがnullだとすると、FIND_IN_SETが発見の結果を返してくることはないはずだからです。
出来れば、test_masterのinitial_kanaには、インデックスをつけておきましょう。
product_idと、test_idの組が一意であるという仮定が、OKであれば、group byは処理を遅くするだけで意味が無いと思います。(意味を補足すると、productテーブルのproduct_idに重複がなく、且つ、test_idにも行内での重複がないという事です。)でも、limitがついていることから、order by am.idが必要になりそうなので、処理時間にはあまり影響しなさそうかな。
本来なら、test_idが、カンマ区切りリストではなく、素直に、一つのidが入った数値カラムだとすれば、idにインデックスが作成されていれば、爆速なはずです。5秒でも遅いといわれそう。
というのを踏まえて、テンポラリーテーブルを作成することも考慮に入れて良いかもしれません。
処理の一環として、product2というテーブルをproductから作成します。
product2のテーブルは、product_id(int)とtest_id(int)からなり、productテーブルのtest_idを展開した物です。このテーブルの主キーはproduct_id,test_idとなります。(product_idは、test_idの個数分だけ重複します。)
product2テーブルに、別途test_idのインデックスもつけておきましょう。
select p.product_id as product_id,
am.id as id
from product2 p join test_master am on am.id=p.test_id
where am.initial_kana = 'あ'
group by am.id
limit 20
offset 0
この構造なら、多分、selectの処理にはほとんど時間を要しません。
問題は、テンポラリーテーブルを作成する時間勝負ですが、多分、トータルではテンポラリーを作る方が早いような気がします。
No.1
- 回答日時:
テーブルの形式は確定ですか?
これではどうやってもスピードがでないと思いますが・・・
productテーブル作り変え
create table product(product_id int ,test_id int,unique (product_id,test_id));
insert into product values(86009,10701),(86009,8545),(84334,12610),(84334,9505),(84334,13326),(84334,9024),(84334,1020747),(84334,6787),(84334,3737),(84334,5266),(85078,1001182),(85078,1002129),(85078,1003064),(84082,24723),(84082,23417),(84082,1002357),(84082,1000683),(84082,1002258),(84082,1003501),(84082,25426),(85072,1008167),(85072,1007194),(85072,1006309),(85072,5240),(85072,1009347),(85072,30212),(85071,28079),(85071,1007881),(85071,1000733),(85071,1002367),(85071,27836),(85071,25141),(85071,29863),(86014,23988),(86014,17802),(86014,26440),(86014,1005928),(86014,22668),(86014,28372),(86014,28135),(83762,1010127),(83762,1010436),(83762,1011554),(83762,1013949),(83762,1014307);
create table test_master(id int,initial_kana varchar(10),index(id,initial_kana));
insert into test_master values(10701,'あ'),(21122,'あ'),(1002129,'あ'),(1002357,'い'),(2291,'い'),(29863,'い'),(23988,'う'),(1010436,'え'),(22299,'え');
test_masterテーブル
create table test_master(id int,initial_kana varchar(10),index(id,initial_kana));
insert into test_master values(10701,'あ'),(21122,'あ'),(1002129,'あ'),(1002357,'い'),(2291,'い'),(29863,'い'),(23988,'う'),(1010436,'え'),(22299,'え');
抽出
select product_id from product as p inner join test_master as tm on tm.id=p.test_id and tm.initial_kana='あ'
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- MySQL 次の時間帯の勝率の合計を求めるSQL文 1 2023/07/04 17:12
- Oracle sqlで質問です。 Aテーブルの情報をBテーブルに更新かけたいです。 やりたいことは、Bテーブルの受 1 2023/05/17 11:17
- MySQL テーブル作成時のカラムについて 2 2022/08/27 21:48
- JavaScript Javascript初心者|jQueryの.val()で値を取得し複数の要素を連結させる方法知りたい 2 2022/06/02 12:06
- Oracle sqlで質問です。 aテーブルとbテーブルがあり、下記のsqlで取得したidとnameに一致しないレ 1 2022/04/20 20:34
- Access(アクセス) アクセス テーブルの空白を変数に置換するボタンが作りたい 4 2022/07/08 11:19
- システム ホームページの仕組みについて 3 2022/08/16 14:33
- Visual Basic(VBA) Selenium Basicの件 5 2023/04/10 20:55
- HTML・CSS ブロックエディターで作りつつ、画像を挿入しつつ、画像にスタイルシートのコードを付ける方法はありますか 1 2022/08/23 18:46
- Access(アクセス) アクセス 削除するレコードを含んだテーブルを指定してくださいのエラー対処方法 1 2022/11/24 15:01
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
タグを記録したテーブルの書き...
-
Webで、図形描画を行いたい。
-
データの連番
-
深い人、浅い人の判断
-
Yes/No型にチェックを入れたい
-
VMware Player でCD-ROMドライ...
-
2つのテーブルを繋げて条件をつ...
-
親と子供が複数のSQL取得方法
-
このようなテーブルを取得するS...
-
Access 複数のフィールドからク...
-
MySQLでのランキングの生成方法...
-
プロシジャー一覧の取得
-
MySQLで特定の条件のレコードを...
-
エクセルで最後の文字だけ置き...
-
ワラスボについて
-
'id'を無視して、外部ファイル...
-
mysql 検索方法
-
MySQLでの複数テーブル(4つ...
-
OracleでINSERT文のループ
-
これなんですか?
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
エクセルで最後の文字だけ置き...
-
エクセルの関数について教えて...
-
select文のwhere句に配列を入れ...
-
VIEWの元のテーブルのindexって...
-
エラー 1068 (42000): 複数の主...
-
SQLにて特定の文字を除いた検索...
-
【Transact-sql】 execの結果を...
-
マイクラPC版のコマンドで効率...
-
SQL Left Join で重複を排除す...
-
sqlで、600行あるテーブルを100...
-
複数テーブルのGROUP BY の使い...
-
WordpressのContact form 7でzi...
-
クエリ表示と、ADOで抽出したレ...
-
SQLサーバから、項目の属性(型...
-
selectした大量データをinsert...
-
Access パラメータクエリをcsv...
-
副問合せの書き方について
-
inner joinをすると数がおかし...
-
insertを高速化させたい
-
[MySQL] 3つのテーブルの結合で...
おすすめ情報