MySQL上に 「url 列に好き勝手にURLが入ったテーブル master」 があります。
その他の列としてid, inserted, nameがあり、insertedとnameが同一となっているレコードも複数存在しています。例えばname=bobが複数のサイト(url)を閲覧した履歴がまとめて登録されて、登録されたレコードは同じ登録日(inserted)になるといった感じです。
ここで、inserted と nameの組み合わせ毎にグルーピングした上で、@aurl, @burl, @curl(中身は文字列で'http://%/default.html'など部分一致用条件)に類似せずtag=0を満たす最小のidを取得します。inserted と nameの組み合わせ自体は複数あるので最初のidも複数得られます。
そうして得られたurlについて?, #以降を割愛した状態で一覧を得たいと思っています。
?, #は入っていないこともありますし、両方はいっていることもあり順不同とします。(数も不定)
以下のようなSQLにて動作はするのですが、もっとエレガントで高速な方法はないでしょうか。
因みに45万レコードからの実行結果は、18.0776 seconds.です。
id(big int), url(text), name(text), inserted(UNIX_TIME=int)にはインデックスが張られています。(textについては256長を指定してインデックス作成)
```SQL
select url from master
where id in (
select min(id) from master
where
url not like @aurl
and url not like @burl
and url not like @curl
and tag = 0
group by inserted, name
)
and url not like '%#%'
and url not like '%?%'
union distinct
select id, inserted, name, left(url, instr(url, '?')-1) from master
where id in (
select min(id) from master
where
url not like @aurl
and url not like @burl
and url not like @curl
and tag = 0
group by inserted, name
)
union distinct
select id, inserted, name, left(url, instr(url, '#')-1) from master
where id in (
select min(id) from master
where
url not like @aurl
and url not like @burl
and url not like @curl
and tag = 0
group by inserted, name
)
and url like '%#%' and url not like '%?%'
;
3つの結果をUNIONしているので18秒ほど掛かっていて、UNIONせずにまとめて列挙できれば高速化できると想像しているのですが、replaceとregexpを組み合わせるような使い方が出来ないためこうしています。 left関数の辺りにたくさんif文を繋げれば出来そうな気もしますが見た目に悪くメンテナンスしづらそうです(もっと完結に書けないでしょうか)。 not likeの周りもregexpで1つにまとめようとしましたが、こちらは逆に遅くなりました(3倍ほど)。
回答2件
あなたの回答
tips
プレビュー