2011-02-07 21 views
1

私は以下のような同様のテーブルスキームを使用するWebアプリケーションを持っています。単に私は記事の選択を最適化したいと思います。記事は与えられたタグに基づいて選択されます。たとえば、タグが 'iphone'の場合、クエリは先月の 'iphone'に関するすべての公開記事を出力するはずです。
MySQLクエリの最適化

CREATE TABLE `article` (
`id` int(11) NOT NULL auto_increment, 
`title` varchar(100) NOT NULL, 
`body` varchar(200) NOT NULL, 
`date` timestamp NOT NULL default CURRENT_TIMESTAMP, 
`author_id` int(11) NOT NULL, 
`section` varchar(30) NOT NULL, 
`status` int(1) NOT NULL, 
PRIMARY KEY (`id`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; 


CREATE TABLE `tags` (
`name` varchar(30) NOT NULL, 
`article_id` int(11) NOT NULL, 
PRIMARY KEY (`name`,`article_id`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8; 


CREATE TABLE `users` (
`id` int(11) NOT NULL auto_increment, 
`username` varchar(30) NOT NULL, 
PRIMARY KEY (`id`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ; 

は私のMySQLのクエリで

explain select article.id,users.username,article.title 
from article,users,tags 
where article.id=tags.article_id and tags.name = 'iphone4' 
and article.author_id=users.id and article.status = '1' 
and article.section = 'mobile' 
and article.date > '2010-02-07 13:25:46' 
ORDER BY tags.article_id DESC 


出力は

id select_type  table type possible_keys key  key_len  ref  rows Extra <br> 
1 SIMPLE tags ref  PRIMARY  PRIMARY  92 const 55 Using where; Using index <br> 
1 SIMPLE article  eq_ref PRIMARY  PRIMARY  4 test.tags.article_id 1 Using where <br> 
1 SIMPLE users eq_ref PRIMARY  PRIMARY  4 test.article.author_id 1  <br> 


では、より多くのそれを最適化することが可能ですか?

+0

は、私にはよさそうです。 –

+0

一般的な規則は、結合および/またはwhere句で使用するフィールドにインデックスを付けることです。しかし、あなたのDBが非常に大きくなるまで、「tags.name」や「article.status」などのインデックスを持たない*などは重要ではありません。しかし、物事が後で減速するなら、それは調べるべきものです。 –

答えて

-1

selectステートメントで参照しているアーティクル内の追加フィールドにインデックスを付けることができます。この場合、私はあなたがこのような記事にインデックスを作成することをお勧め:

CREATE INDEX article_idx ON article (author_id, status, section, date); 

インデックスは、あなたが扱っているどのように多くの全体的な記録に応じて、クエリをスピードアップする必要があることを作成します。私の理解から、適切にインデックスを作成するには、作成したクエリを調べ、where句の一部であるカラムのインデックスを作成する必要があります。これは、クエリオプティマイザが一般的にクエリをよりうまく処理するのに役立ちます。しかし、そうすることは非効率的で効果的ではないので、個々の列ごとにインデックスを作成することを意味するわけではありません。可能であれば、selectステートメントを表す複数の列インデックスを作成します。

+0

usef_ksaが指摘した唯一のクエリは、キーワードと記事の日付を使用することです。そのクエリは、あなたが提案するインデックスではありません。 – symcbean

+0

元の質問では、where句は特に記事内の4つのフィールドすべてを調べています。 4つすべてが別のテーブルに結合されるわけではありませんが、実際のクエリでは4つすべてが使用されます。クエリでそのインデックスを使用しないのはなぜですか?主キーの一部ではない、照会されている残りのフィールドを索引付けします。 – dmcnelis

0

このクエリは、より選択的である状況に応じて、最適化することができる:tags.name = 'iphone4'またはarticle.date > '2010-02-07 13:25:46'

以下の記事がある場合は、Feb 7後に掲載さよりもiphoneをタグ付け、その後、元のクエリがいいです。

多くの記事がある場合

iphoneをタグ付けされたが、いくつかは、これらの Feb 7後、このクエリは、より効率的になります投稿: ORDER BY条件が変更されたことを

SELECT article.id, users.username, article.title 
FROM tags 
JOIN article 
ON  article.id = tags.article_id 
     AND article.status = '1' 
     AND article.section = 'mobile' 
     AND article.date > '2010-02-07 13:25:46' 
JOIN users 
ON  users.id = article.author_id 
WHERE tags.name = 'iphone4' 
ORDER BY 
     tags.article_date DESC, tags.article_id DESC 

注意を。これはあなたが望むものかもしれませんが、一般にiddateの注文はお互いに対応しています。

元のORDER BY状態が本当に必要な場合は、そのまま残してもかまいませんが、filesortが追加されます(または元の計画に戻る)。いずれの場合も

article (status, section, date, id) 
0

にクエリをインデックスを作成する必要があり、出力先月から「iphone」についての開いているすべての記事。

このデータで実行する唯一のクエリは、タグと日付を使用します。タグテーブルのタグのインデックスがありますが、日付は別のテーブルに格納されています(記事 - 名前付けスキーマと少し矛盾しています)。記事テーブルに日付を使用してインデックスを追加すると、何のメリットもありません。 idを使用すると、日付が(この順番で)少しは助けになりますが、本当に速く実行するためには、日付をタグテーブルに非正規化する必要があります。

大量のデータセットを定期的に移動しない限り、現在のタイムスタンプのデフォルトのdatetime列をタグテーブルに追加するだけです。

多くの他の方法でデータとやりとりしたいと思うかもしれません。実際には、低速のクエリログに低い(no?)しきい値を設定し、結果のデータを分析してパフォーマンスの問題(最初に継続時間^ 2 *の最高値を持つクエリを調べてみてください)。

スクリプトは、この分析に有用である、それ以下のURLであります。

http://www.retards.org/projects/mysql/