1

MySQL やデータベース全般についてはまだあまり経験がありませんが、大規模な Web アプリの開発に取り掛かるつもりです。以下は、ユーザーが他のユーザーを検索できるようにする私のアプリの検索クエリです。このクエリのプライマリ テーブルにdev_Profileは約 14,000 行あるため、クエリはかなり遅くなります (可能な限り最大のセットを返すクエリを実行すると約 5 秒)。ここで行うことができる多くの最適化の微調整があると確信していますが、インデックスを作成することは、ここで行う最も基本的な最初のステップでしょうか? 私は最初、自分でインデックスについて学び、複数の結合を持つクエリのインデックスを作成する方法を学ぼうとしましたが、それを完全に把握していません。実際のクエリのコンテキストで物事を見ることが、より教育的なものになることを願っています。

基本的なクエリは次のとおりです。

SELECT 
  dev_Profile.ID AS pid,
  dev_Profile.Name AS username,
  IF(TIMESTAMPDIFF(SECOND, st1.lastActivityTime, UTC_TIMESTAMP()) > 300 OR ISNULL(TIMESTAMPDIFF(SECOND, st1.lastActivityTime, UTC_TIMESTAMP())), 0, 1) AS online, 
  FLOOR(DATEDIFF(CURRENT_DATE, dev_Profile.DOB) / 365) AS age,
  IF(dev_Profile.GenderID=1, 'M', 'F') AS sex, 
  IF(ISNULL(st2.Description), 0, st2.Description) AS relStatus, 
  st3.Name AS country, 
  IF(dev_Profile.RegionID > 0, st4.Name, 0) AS region, 
  IF(dev_Profile.CityID > 0, st5.Name, 0) AS city, 
  IF(ISNULL(st6.filename), 0, IF(st6.isApproved=1 AND st6.isDiscarded=0 AND st6.isModerated=1 AND st6.isRejected=0 AND isSizeAvatar=1, 1, 0)) AS hasPhoto, 
  IF(ISNULL(st6.filename), IF(dev_Profile.GenderID=1, 'http://www.mysite.com/lib/images/avatar-male-small.png', 'http://www.mysite.com/lib/images/avatar-female-small.png'), IF(st6.isApproved=1 AND st6.isDiscarded=0 AND st6.isModerated=1 AND st6.isRejected=0 AND isSizeAvatar=1, CONCAT('http://www.mysite.com/uploads/', st6.filename), IF(dev_Profile.GenderID=1, 'http://www.mysite.com/lib/images/avatar-male-small.png', 'http://www.mysite.com/lib/images/avatar-female-small.png'))) AS photo,
  IF(ISNULL(dev_Profile.StatusMessage), IF(ISNULL(dev_Profile.AboutMe), IF(ISNULL(st7.AboutMyMatch), 0, st7.AboutMyMatch), dev_Profile.AboutMe), dev_Profile.StatusMessage) AS text
FROM 
  dev_Profile 
  LEFT JOIN dev_User AS st1 ON st1.ID = dev_Profile.UserID 
  LEFT JOIN dev_ProfileRelationshipStatus AS st2 ON st2.ID = dev_Profile.ProfileRelationshipStatusID 
  LEFT JOIN Country AS st3 ON st3.ID = dev_Profile.CountryID 
  LEFT JOIN Region AS st4 ON st4.ID = dev_Profile.RegionID 
  LEFT JOIN City AS st5 ON st5.ID = dev_Profile.CityID 
  LEFT JOIN dev_Photos AS st6 ON st6.ID = dev_Profile.PhotoAvatarID 
  LEFT JOIN dev_DesiredMatch AS st7 ON st7.ProfileID = dev_Profile.ID
WHERE 
  dev_Profile.ID != 11222 /* $_SESSION['ProfileID'] */
  AND st1.EmailVerified = 'true'
  AND st1.accountIsActive=1
ORDER BY st1.lastActivityTime DESC LIMIT 900;

このクエリの速度 (ご覧のとおり遅すぎます):

900 rows in set (5.20 sec)

このクエリの EXPLAIN:

+----+-------------+-------------+--------+---------------+---------+---------+---------------------------------------------+-------+----------------------------------------------+
| id | select_type | table       | type   | possible_keys | key     | key_len | ref                                         | rows  | Extra                                        |
+----+-------------+-------------+--------+---------------+---------+---------+---------------------------------------------+-------+----------------------------------------------+
|  1 | SIMPLE      | dev_Profile | range  | PRIMARY       | PRIMARY | 4       | NULL                                        | 13503 | Using where; Using temporary; Using filesort |
|  1 | SIMPLE      | st2         | eq_ref | PRIMARY       | PRIMARY | 1       | syk.dev_Profile.ProfileRelationshipStatusID |     1 |                                              |
|  1 | SIMPLE      | st3         | eq_ref | PRIMARY       | PRIMARY | 4       | syk.dev_Profile.CountryID                   |     1 |                                              |
|  1 | SIMPLE      | st4         | eq_ref | PRIMARY       | PRIMARY | 4       | syk.dev_Profile.RegionID                    |     1 |                                              |
|  1 | SIMPLE      | st5         | eq_ref | PRIMARY       | PRIMARY | 4       | syk.dev_Profile.CityID                      |     1 |                                              |
|  1 | SIMPLE      | st1         | eq_ref | PRIMARY       | PRIMARY | 4       | syk.dev_Profile.UserID                      |     1 | Using where                                  |
|  1 | SIMPLE      | st6         | eq_ref | PRIMARY       | PRIMARY | 4       | syk.dev_Profile.PhotoAvatarID               |     1 |                                              |
|  1 | SIMPLE      | st7         | ALL    | NULL          | NULL    | NULL    | NULL                                        |   442 |                                              |
+----+-------------+-------------+--------+---------------+---------+---------+---------------------------------------------+-------+----------------------------------------------+

ユーザーの検索に追加の基準が含まれている場合、クエリにさらに多くのWHEREand句を含めることもできます。HAVING追加の節は次のとおりです (例の値で設定):

AND dev_Profile.GenderID = 1 
AND dev_Profile.CountryID=127
AND dev_Profile.RegionID=36
AND dev_Profile.CityID=601
HAVING (age >= 18 AND age <= 50)
AND online=1 
AND hasPhoto=1 

WHEREこれは、可能なすべてのandHAVING句を使用したクエリの EXPLAIN です。

+----+-------------+-------------+--------+---------------+---------+---------+---------------------------------------------+-------+----------------------------------------------+
| id | select_type | table       | type   | possible_keys | key     | key_len | ref                                         | rows  | Extra                                        |
+----+-------------+-------------+--------+---------------+---------+---------+---------------------------------------------+-------+----------------------------------------------+
|  1 | SIMPLE      | dev_Profile | range  | PRIMARY       | PRIMARY | 4       | NULL                                        | 13503 | Using where; Using temporary; Using filesort |
|  1 | SIMPLE      | st2         | eq_ref | PRIMARY       | PRIMARY | 1       | syk.dev_Profile.ProfileRelationshipStatusID |     1 |                                              |
|  1 | SIMPLE      | st3         | const  | PRIMARY       | PRIMARY | 4       | const                                       |     1 |                                              |
|  1 | SIMPLE      | st4         | const  | PRIMARY       | PRIMARY | 4       | const                                       |     1 |                                              |
|  1 | SIMPLE      | st5         | const  | PRIMARY       | PRIMARY | 4       | const                                       |     1 |                                              |
|  1 | SIMPLE      | st1         | eq_ref | PRIMARY       | PRIMARY | 4       | syk.dev_Profile.UserID                      |     1 | Using where                                  |
|  1 | SIMPLE      | st6         | eq_ref | PRIMARY       | PRIMARY | 4       | syk.dev_Profile.PhotoAvatarID               |     1 |                                              |
|  1 | SIMPLE      | st7         | ALL    | NULL          | NULL    | NULL    | NULL                                        |   442 |                                              |
+----+-------------+-------------+--------+---------------+---------+---------+---------------------------------------------+-------+----------------------------------------------+

これがTMIなのか十分でないのかさえわかりません。

インデックスはここで取るべき正しいステップですか? もしそうなら、誰かが私を正しい方向に導くことができますか?

4

2 に答える 2

1

正しいステップは、クエリを高速化することです!

dev_Profile元のクエリでは、テーブルにインデックス可能な条件がないため、テーブルでテーブルスキャンを実行することになります。変更されたクエリでは、列で許可されているさまざまな値の数に依存します。重複する可能性がある場合、残りのクエリを完了するためにとにかくテーブルをフェッチする必要があるため、インデックスが使用されない可能性があります。

私はあなたの計画を正しく読んだので、すでにインデックス付きのnull不可の列に他のすべてのテーブルを結合しています(何らかの理由でインデックスを使用していないように見えるst7を除く)。したがって、左結合を使用すべきではないように見えます。(EmailVerified, accountIsActive, lastActivityTime)これにより、 tableのインデックスを使用できるようになりますst1

于 2012-10-28T00:13:38.143 に答える
0

頻繁なクエリに関連するインデックスを使用する必要があります。インデックスは書き込みパフォーマンスをわずかに低下させますが、検索は大幅に高速化されます。経験則として、オブジェクト自身の ID は PRIMARY キーとしてインデックスを作成する必要があり、クエリで常に一緒に表示される列グループにインデックスを作成することをお勧めします。GenderID、CountryID、RegionID、CityID、age、online、および hasPhoto をインデックス化する必要があると思います。適切なインデックスが使用されていないと思われる場合は、少なくとも dev_Profile のスキーマを提供する必要があります。

国/地域/都市 ID は冗長な情報を表している可能性があることに注意してください。あなたのデザインは最適ではないかもしれません。

注意 2: SELECT で非常に多くのアプリケーション ロジックを実行しています。SQL は、これらの多数の IF-in-IF-in-IF 句用に設計されていません。また、URL のために、クエリは、関連するフィールド (つまり、ファイル名、genderID など) を要求した場合よりもはるかに大きなテーブルを返します。の上)。正確に解釈された値をクエリによって返さなければならない場合があります。一般に、(速度と読みやすさの面で) これらの処理手順をアプリケーション コードにコーディングした方がよいでしょう。

于 2012-10-28T00:15:26.073 に答える