2016-10-01 5 views
-2

私はmysqlデータベースで117秒以上かかるこのクエリを持っています。より速い結果のためのサブクエリ

select users.*, users_oauth.* FROM users LEFT JOIN users_oauth ON users.user_id = users_oauth.oauth_user_id WHERE (

      (MATCH (user_email) AGAINST ('sometext')) OR 
      (MATCH (user_firstname) AGAINST ('sometext')) OR 
      (MATCH (user_lastname) AGAINST ('sometext'))) 

    ORDER BY user_date_accountcreated DESC LIMIT 1400, 50 

サブクエリを最適化するためにどのように使用できますか?

3つのフィールドは、フルテキストです:

ALTER TABLE `users` ADD FULLTEXT KEY `email_fulltext` (`user_email`); 
ALTER TABLE `users` ADD FULLTEXT KEY `firstname_fulltext` (`user_firstname`); 
ALTER TABLE `users` ADD FULLTEXT KEY `lastname_fulltext` (`user_lastname`); 

異なるテーブルのユーザーフィールドで検索するには、ウェブサイトで唯一の検索入力があります。

制限がたとえばLIMIT 0,50の場合、クエリは3秒未満で実行されますが、LIMITが増加するとクエリが非常に遅くなります。

ありがとうございました。

FULLTEXT(user_email, user_firstname, user_lastname) 

そして、ちょうど1に3試合を変更:

+1

このクエリでEXPLAINを実行して結果を掲載できますか? – Besi

+1

列がどのテーブルから来るのかを特定します。 –

+0

検索対象のフィールドに全文索引が作成されていますか? – Shadow

答えて

0

は、単一のFULLTEXTインデックスを使用しORDER BY ... DESC LIMIT 1400, 50

MATCH (user_email, user_firstname, user_lastname) AGAINST ('sometext') 

をここでは別の問題です。 pagination via OFFSETの邪悪について読むそれには回避策がありますが、それがあなたの声明に当てはまるかどうかは疑問です。

本当に何千ものユーザーがテキストに一致していますか?誰か(検索エンジンロボット以外)は実際に29ページを表示しますか?本当にそのような長いUIを持つのが理にかなっているかどうかを考えてみてください。

第3号。 「遅延評価」を検討してください。つまり、最初にユーザIDを見つけ、、次にに戻ってusersusers_oauthに戻って残りの列を取得します。派生テーブルにはMATCHという単一のSELECT、次に2つのテーブルに対してはJOINとなります。 ORDER BYLIMITが派生テーブルに含まれる場合、大きな勝利になる可能性があります。

各列がどの表に属しているかを明記してください。最後の段落は、日付列について知らないため不正確です。

更新

2番目の試みで、あなたは大幅に物事を遅くされ、ORを追加しました。新しい減速を避けるために、これをUNIONに変えましょう。まずみましょうUNIONデバッグ:

(SELECT * -- no mention of oauth columns 
    FROM users -- No JOIN 
    WHERE users.user_id LIKE ... 
    ORDER BY user_id DESC 
    LIMIT 0, 50 
) 
UNION ALL 
(SELECT * -- no mention of oauth columns 
    FROM users 
    WHERE MATCH ... 
    ORDER BY user_id DESC 
    LIMIT 0, 50 
) 

個別SELECTタイミングによってテストし、それを。そのうちの1人がまだ遅い場合は、それに集中しましょう。次に、UNIONをテストします。 (これは、mysqlコマンドラインツールを使用する方がPHPよりも便利な場合です。)

それぞれを分割することによって、それぞれSELECTが最適なインデックスを使用できます。 UNIONには若干のオーバーヘッドがありますが、おそらくORという非効率性を下回ります。

ここでusers_oauthを折りたたんでみましょう。

最初に、あなたは非常に重要であると思われるINDEX(oauth_user_id)。それを加えなさい!

ここでそれらをまとめてみましょう。

SELECT u.* 
    FROM (.... the entire union query ...) AS u 
    LEFT JOIN users_oauth ON users.user_id = users_oauth.oauth_user_id 
    ORDER BY user_id DESC -- yes, repeat 
    LIMIT 0, 50    -- yes, repeat 
+0

ありがとうリック、テーブルの列に返信を追加しました –

+0

更新を参照..... –

+0

どう思いましたか?確かに私は 'INDEX(oauth_user_id)'を忘れていましたが、今この要求は0.6615秒です:) リックありがとう、今私はUNION ALLとどのように管理するかを理解しています。 :) –

0

はい@Rick

私はにインデックスフルテキストを変更:

ALTER TABLE `users` 
    ADD FULLTEXT KEY `fulltext_adminsearch` (`user_email`,`user_firstname`,`user_lastname`); 

そして今、いくつかのPHPの条件、$ _POST [ '検索']空にすることができますがあります:

if(!isset($_POST['search'])) { 
    $searchId = '%' ; 
} else { 
    $searchId = $_POST['search'] ; 
} 
$searchMatch = '+'.str_replace(' ', ' +', $_POST['search']); 
$sqlSearch = $dataBase->prepare(
     'SELECT users.*, users_oauth.* 
      FROM users 
      LEFT JOIN users_oauth ON users.user_id = users_oauth.oauth_user_id 
      WHERE ( users.user_id LIKE :id OR 
        (MATCH (user_email, user_firstname, user_lastname) 
          AGAINST (:match IN BOOLEAN MODE))) 
      ORDER BY user_id DESC LIMIT 0,50') ; 

$sqlSearch->execute(array('id' => $searchId, 
          'match' => $searchMatch)) ; 

users_oauthテーブルには、user_idの列があります。

表のユーザー:

+--------------------------+-----------------+------+-----+---------+----------------+ 
    | Field     | Type   | Null | Key | Default | Extra   | 
    +--------------------------+-----------------+------+-----+---------+----------------+ 
    | user_id     | int(8) unsigned | NO | PRI | NULL | auto_increment | 
    | user_activation_key  | varchar(40)  | YES |  | NULL |    | 
    | user_email    | varchar(40)  | NO | UNI |   |    | 
    | user_login    | varchar(30)  | YES |  | NULL |    | 
    | user_password   | varchar(40)  | YES |  | NULL |    | 
    | user_firstname   | varchar(30)  | YES |  | NULL |    | 
    | user_lastname   | varchar(50)  | YES |  | NULL |    | 
    | user_lang    | varchar(2)  | NO |  | en  
    +--------------------------+-----------------+------+-----+---------+----------------+ 

表のusers_oauth:

+----------------------+-----------------+------+-----+---------+----------------+ 
| Field    | Type   | Null | Key | Default | Extra   | 
+----------------------+-----------------+------+-----+---------+----------------+ 
| oauth_id    | int(8) unsigned | NO | PRI | NULL | auto_increment | 
| oauth_user_id  | int(8) unsigned | NO |  | NULL |    | 
| oauth_google_id  | varchar(30)  | YES | UNI | NULL |    | 
| oauth_facebook_id | varchar(30)  | YES | UNI | NULL |    | 
| oauth_windowslive_id | varchar(30)  | YES | UNI | NULL |    | 
+----------------------+-----------------+------+-----+---------+----------------+ 

左が長い参加、要求がwihtout 0,0158秒と3秒かかります。

50行ごとにSQLリクエストを作成するほうが速いでしょう。

サブクエリでより高速になるでしょうか?サブクエリでそれを作る方法は?

ありがとうございました

関連する問題