feedというテーブルには
site_name, site_url, feed_name, feed_url, date, count
feed_urlがプライマリーの6つのフィールドがあり、
siteというテーブルには
site_name, site_url, first_date, last_date
site_urlがプライマリーの4つのフィールドがあります。
feedテーブルのsite_urlとsiteテーブルのsite_urlには全く同じものが入っています。
この二つのテーブルを用いて、以下のような条件でレコードを取り出したいです。
・site_urlごとのfeed.countの平均値を取得
・取得した平均値をソート(DESC)
・一週間前までのfeed.dateの中から
・site_urlとsite_nameとfirst_dateとlast_dateと算出した平均値を取り出したい
以下のようなSQL文を作ってphpMyAdminから実行してみたのですが、2秒ほどかかってしまいました。より高速に取り出すことはできますでしょうか?
//0.5程度で終わる
//これプラスsiteテーブルのfirst_dateとlast_dateも取り出したい。
SELECT site_name, site_url, AVG( count )
FROM `feed`
WHERE DATE > '2011-01-10 00:00:00'
GROUP BY site_url
ORDER BY AVG( count ) DESC
LIMIT 0 , 30
//2秒ほどかかる
//目的のレコードが取り出せる。
//このSQLを高速化したい。
SELECT site.first_date, site.last_date, feed.site_name, feed.site_url, AVG( feed.count )
FROM `feed` , `site`
WHERE feed.date > '2011-01-10 00:00:00'
AND feed.site_url = site.site_url
GROUP BY feed.site_url
ORDER BY AVG( feed.count ) DESC
LIMIT 0 , 30
できれば1秒以内が理想なのですが、そこまで高速にすることは可能でしょうか?
もし可能な場合は、そのSQL文を教えて頂ければ幸いです。(1秒以内でなくても高速になれば嬉しいです。)
よろしくお願いします。
No.1ベストアンサー
- 回答日時:
こんばんは。
まぁ、普通に書けば・・・、
select first_date, last_date, feed.site_name, feed.site_url, avg_cnt
from site
inner join
(select site_name, site_url, avg( count ) as avg_cnt
from feed
where date > '2011-01-10 00:00:00'
group by site_url) feed
on (site.site_url = feed.site_url)
order by avg_cnt desc
limit 0, 30
こうなるわなぁ・・・。
SQLのチューニングもそうですが、件数やカーディナリティによって、適切にINDEXを付けると効果的です。
まずは実行計画などを見て、どこにコストがかかっているかを見てください。
ちなみにSQLの最初に、EXPLAIN SELECT・・・で書き始めると見られます・・・。
凄いですね…0.5秒くらいで取り出せました!ありがとうございます。
質問の内容的にはこれで解決→終りなのですが、もう少しだけ質問させてください。
EXPLAINをつけて実行すると、下記のようなテーブルが表示されたのですが、googleさんに聞いてみてもどこがどうなって、どう直せばいいのかさっぱりでした…。
※プレーンテキストだと整形がうまくいきそうにないのでHTMLで失礼します。
<html>
<head>
<style>
td,th{padding:0 8px;border:1px solid #000;}
</style>
</head>
<body>
<table>
<tr><th>id</th><th>select_type</th><th>table</th><th>type</th><th>possible_keys</th><th>key</th><th>key_len</th><th>ref</th><th>rows</th><th>Extra</th></tr>
<tr>
<td align="right" class=" nowrap">1</td>
<td class="">PRIMARY</td>
<td class=""><derived2></td>
<td class="">ALL</td>
<td class=""><i>NULL</i></td>
<td class=""><i>NULL</i></td>
<td class=""><i>NULL</i></td>
<td class=""><i>NULL</i></td>
<td align="right" class=" nowrap">257</td>
<td class="">Using filesort</td>
</tr>
<tr>
<td align="right" class=" nowrap">1</td>
<td class="">PRIMARY</td>
<td class="">site</td>
<td class="">eq_ref</td>
<td class="">PRIMARY</td>
<td class="">PRIMARY</td>
<td class="">767</td>
<td class="">feed.site_url</td>
<td align="right" class=" nowrap">1</td>
<td class=""> </td>
</tr>
<tr>
<td align="right" class=" nowrap">2</td>
<td class="">DERIVED</td>
<td class="">feed</td>
<td class="">ALL</td>
<td class=""><i>NULL</i></td>
<td class=""><i>NULL</i></td>
<td class=""><i>NULL</i></td>
<td class=""><i>NULL</i></td>
<td align="right" class=" nowrap">487226</td>
<td class="">Using where; Using temporary; Using filesort</td>
</tr>
</table>
</body>
</html>
さらに高速にすることが可能ということでしょうか?
feedテーブルは487226件のレコードがあり、
siteテーブルは287件のレコードがあります。
No.4
- 回答日時:
こんにちは。
既に#2、#3さんが回答を出しておられますが・・・、
実行計画を見ると、
1.feedテーブルの検索がINDEXなし(ALL)、487226件
2.siteテーブルの検索がPRIMARY、1件
3.結合後にUsing filesort、257件
となっております。
2は問題なし。
3は致し方なし(ORDER BYに含まれるカラムにINDEXを付けられればいいのですが、この場合はAVGの計算結果のため、無理という事。件数的にも少ないので、許容範囲)・・・。
1は問題あり。
です。
実行計画の結果は、このように見る事ができます。
2度も回答ありがとうございました。
INDEXとか正直全然わかってなかったので、これを期に基本的な部分を勉強していきたいと思いました。
本当にどうもありがとうございます。
ベストアンサーはかなり迷いましたが、回答内容で比べることがちょっと難しかったので、時間的に先に回答をくれたtaka451213さんを選ばせてもらいました。
No.2
- 回答日時:
出されている情報だけでは実行時間を短縮できるかどうかは分かりません。
まず、EXPLAINで現在の実行計画を取得して見てください。
後、これは推測になりますが`feed` に(`DATE`,`site_url`)で索引を作成し、
SELECT site.first_date, site.last_date, F.site_name, F.site_url, F.AVG_COUNT
FROM
( SELECT feed.site_name, feed.site_url, AVG( feed.count ) AVG_COUNT
FROM `feed`
WHERE feed.date > '2011-01-10 00:00:00'
GROUP BY feed.site_url ) F INNER JOIN `site` ON F.site_url = site.site_url
ORDER BY F.AVG_COUNT DESC
LIMIT 0 , 30
とした方がもしかすると実行時間は少なくてすむかもしれません。
(あまり根拠ありませんが)
お二人とも凄いですね…どちらのSQL文も0.5秒くらいでおわりました。ありがとうございます。
`DATE`,`site_url`で索引というのは単純にインデックスをつけるだけでよいのでしょうか?
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- CGI perlで書いたcgiでsqliteの使い方を教えてください 2 2023/05/08 21:29
- その他(プログラミング・Web制作) Pythonで会員サイトの自動ログイン ID Nameがない 1 2022/12/16 02:09
- その他(プログラミング・Web制作) python 2 2022/12/23 09:06
- その他(プログラミング・Web制作) python flask から fastapiへの移行時のエラー対処 1 2023/02/05 12:26
- Ruby 教えてください 2 2023/01/04 17:50
- Visual Basic(VBA) データベースから絞り込んでデータを読み込み 1 2023/02/21 19:51
- Oracle sqlで質問です。 aテーブルとbテーブルがあり、下記のsqlで取得したidとnameに一致しないレ 1 2022/04/20 20:34
- 英語 The SD reamer drill with stopper may also be used 3 2022/04/22 09:40
- PHP プログラムコードを入力する場合改行してもいいですか? 2 2022/10/02 16:05
- MySQL SQLです。こんな感じですか?あってますか? うまくいきません教えてくださいお願いします 1 2023/07/08 15:27
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
BLOB型のPDF出力の方法
-
Excel 2019 のピボットテーブル...
-
エクセルVBAで5行目からオート...
-
「直需」の意味を教えてください
-
Accessでテーブル名やクエリ名...
-
Oracle 2つのDate型の値の差を...
-
Accessクエリでの、LIKE条件
-
ExcelのデータをコピーでACCESS...
-
Accessのリンクテーブルのパス...
-
ORACLEでLONG項目からCHAR項目...
-
アクセスのコンボボックスのデ...
-
エクセルグラフの凡例スペース
-
Accessでコードを入れると名前...
-
Access テキスト型に対する指定...
-
異なるサーバのDBデータ同士を...
-
テーブルの存在チェックについて
-
Accessでテーブルの値をテキス...
-
Excelで空白以外の値がある列の...
-
アクセス エラーを数値「0」に...
-
Vbaでアクセスからエクセルにリ...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
BLOB型のPDF出力の方法
-
エクセル内のURLからHPのタイト...
-
TortoiseSVNのリポジトリブラウ...
-
リバースプロクシを使って接続...
-
autorun がうまく動作しない
-
Excel 2019 のピボットテーブル...
-
「直需」の意味を教えてください
-
エクセルVBAで5行目からオート...
-
Accessでテーブル名やクエリ名...
-
Accessでテーブルの値をテキス...
-
Oracle 2つのDate型の値の差を...
-
セルの右クリックで出る項目を...
-
Access テキスト型に対する指定...
-
作番ってどういう意味でしょうか?
-
Accessでコードを入れると名前...
-
Accessのフィールド数が255しか...
-
Accessのリンクテーブルのパス...
-
テーブルの存在チェックについて
-
ACCESSのクエリで集計で、先頭...
-
ACCESSで400以上のフィールドが...
おすすめ情報