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

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

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

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

Q&A

2回答

2961閲覧

MySQLで大量のデータに対して大量のキーワードでフィルタリングする方法

退会済みユーザー

退会済みユーザー

総合スコア0

MySQL

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

0グッド

2クリップ

投稿2015/08/27 06:52

編集2015/08/27 07:31

MySQLで商品を扱うようなテーブルがあります。

SQL

1CREATE TABLE tb_items 2 ( 3 ID int NOT NULL, 4 Name varchar(256), 5 Brand varchar(32), 6 Category varchar(32), 7 Status boolean, 8 PRIMARY KEY(ID), 9 INDEX(Name, Brand, Category) 10 )

上記カラムの意味は順に、「商品ID, 商品名, 製造元, カテゴリ, ステータス」となります。
このテーブルにはデータが数百万件入っているとします。

もう一つ、上記テーブルをキーワードでフィルタリングするためのキーワード用テーブルがあります。

SQL

1CREATE TABLE tb_filter_keyword 2 ( 3 ID int NOT NULL auto_increment, 4 Keyword varchar(24), 5 Type varchar(8), 6 PRIMARY KEY(ID), 7 INDEX(Keyword) 8 )

上記カラムの意味は順に「キーワード, フィルターを掛けるカラム名」となります。
「フィルターを掛けるカラム名」とは、tb_itemsのどのカラムに対してフィルタリングするかという意味で、値は「Name, Brand, Category」が入ります。

そしてこのテーブルにはキーワードが1万件入っているとします。


ここから質問なのですが、数百万件あるtb_itemsの全行に対して、tb_filter_keywordのキーワードがName, Brand, Categoryのいずれかに含まれる場合、その行のStatusを1に、含まない場合は0にしたいです。

このようなクエリーはfor文で回してLIKE %keyword%で検索し、一つずつ更新していくしかないのでしょうか?

それとももっと効率の良い方法などがあるのでしょうか?

テンポラリーテーブルを作ったり、抽出した新たなテーブルを作ったり、など効率が良ければどのような方法でも構いません。商品数が数百万件、キーワードが1万件ありますので効率の良い方法をお聞きしたいです。

どうぞよろしくお願い致します。

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

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

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

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

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

anonymouskawa

2015/08/27 07:08

両方のテーブルのPK、インデックス、ユニーク等の設定を教えていただけますか?
退会済みユーザー

退会済みユーザー

2015/08/27 07:30

ご指摘ありがとうございます。質問部分を修正致しました。 どうぞよろしくお願い致します。
guest

回答2

0

tb_itemsを520447件と
tb_filter_keywordを65246件で試しました。

50万件なので、実際の性能は私が試した環境よりも劣ると思います。

SQL

1update tb_items i 2set i.Status = 0 3where 4not exists 5 (select * from tb_filter_keyword f 6 where case when f.Type = 'Name' then 7 i.Name like concat('%', f.keyword, '%') 8 when f.Type = 'Brand' then 9 i.Brand like concat('%', f.keyword, '%') 10 when f.type = 'Category' then 11 i.Category like concat('%', f.keyword, '%') 12 end 13 )

SQL

1update tb_items i 2set i.Status = 1 3where 4 exists 5 (select * from tb_filter_keyword f 6 where case when f.Type = 'Name' then 7 i.Name like concat('%', f.keyword, '%') 8 when f.Type = 'Brand' then 9 i.Brand like concat('%', f.keyword, '%') 10 when f.type = 'Category' then 11 i.Category like concat('%', f.keyword, '%') 12 end 13 )

時間がなくてあまり正確な検証をしていないので、
参考程度に見ていただければと思います。

投稿2015/08/27 09:28

anonymouskawa

総合スコア856

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

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

退会済みユーザー

退会済みユーザー

2015/08/27 10:40

ありがとうございます! わざわざ実データでチェックしていただいて感謝します! 非常に簡潔なクエリーで可能なのですね…。 私も実データを用意できたらチェックしたいと思います。 非常に助かりました、どうもありがとうございます!
guest

0

先にすべてのSTATUSをFALSEにしておいて

下記SQLでフィルタに引っかかった商品だけTRUEにするとかはいかがでしょう?

SQL

1UPDATE tb_items 2 SET Status = TRUE 3FROM ( 4 SELECT 5 SRC.ID 6 FROM tb_items SRC 7 JOIN tb_filter_keyword FIL 8 /* フィルタで指定されたカラムにキーワードが含まれることのチェック */ 9 ON FIL.Type = 'Name' AND locate(FIL.Keyword, SRC.Name) > 0 10 OR FIL.Type = 'Brand' AND locate(FIL.Keyword, SRC.Brand) > 0 11 OR FIL.Type = 'Category' AND locate(FIL.keyword, SRC.Category) > 0 12) TMP 13WHERE ID = TMP.ID 14

UPDATE一回で済ませたいならこちら

SQL

1UPDATE tb_items 2 SET Status = TMP2.Status 3FROM ( 4 SELECT 5 ID 6 /* 最大値が0(フィルタにデータかかかっていない)場合にFALSE,それ以外はTRUEを設定 */ 7 , CASE WHEN MAX(TMP.INC) = 0 THEN FALSE ELSE TRUE END Status 8 FROM ( 9 SELECT 10 ID 11 /* フィルタに引っかかったデータIDに1を設定 */ 12 , 1 INC 13 FROM tb_items SRC 14 JOIN tb_filter_keyword FIL 15 /* フィルタで指定されたカラムにキーワードが含まれることのチェック */ 16 ON FIL.Type = 'Name' AND locate(FIL.Keyword, SRC.Name) > 0 17 OR FIL.Type = 'Brand' AND locate(FIL.Keyword, SRC.Brand) > 0 18 OR FIL.Type = 'Category' AND locate(FIL.keyword, SRC.Category) > 0 19 UNION ALL 20 SELECT 21 ID 22 /* すべてのIDでデータが見つからない場合の初期値(0)を設定 */ 23 , 0 24 FROM tb_items 25 ) TMP 26 GROUP BY 27 ID 28) TMP2 29WHERE ID = TMP2.ID 30

投稿2015/08/27 07:37

編集2015/08/28 01:03
kutsulog

総合スコア985

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

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

退会済みユーザー

退会済みユーザー

2015/08/27 10:37

ありがとうございます! UPDATE1回で済ませられるんですね…! なかなかこのクエリーは思いつかないです…。 まだデータが用意できていないのでこちらのクエリーを試せませんが、近々用意できるのでぜひ試してみたいと思っています。 それとクエリーの意味も…。 とても助かりました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

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

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

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問