2016-10-01 87 views
-2

我有這個查詢,這需要我超過117秒的mysql數據庫。子查詢更快的結果

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增加時查詢變得非常緩慢。

謝謝。

+1

你能用這個查詢運行EXPLAIN併發布結果嗎? – Besi

+1

並確定列來自哪些表。 –

+0

您是否在全部搜索字段上創建了全文索引? – Shadow

回答

0

使用單一FULLTEXT指數:

FULLTEXT(user_email, user_firstname, user_lastname) 

並更改3場比賽只是一個:

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

這裏的另一個問題:ORDER BY ... DESC LIMIT 1400, 50。閱讀關於pagination via OFFSET的罪惡。這有一個解決方法,但我懷疑它是否適用於你的陳述。

你真的有成千上萬的用戶與文本匹配嗎?有人(除了搜索引擎機器人)是否真的翻閱了29頁?想想真的有這樣一個冗長的用戶界面是否有意義。

第3期。考慮「懶惰的評估」。也就是說,首先找到用戶ID,然後然後返回到usersusers_oauth以獲取其餘列。這將是一個單獨的SELECTMATCH在派生表中,然後JOIN到兩個表中。如果ORDER BYLIMIT可以在派生表中,那可能是一個巨大的勝利。

請指出每一列屬於哪一個表 - 我的最後一段由於不知道日期列而不準確。

更新

在你的第二次嘗試,你添加OR,從而大大減緩下來。讓我們把它變成UNION,以避免新的放緩。首先,讓我們調試UNION:通過單獨計時每SELECT

(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 
) 

測試它。如果其中一個仍然很慢,那麼讓我們來關注它。然後測試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 |    | 
+----------------------+-----------------+------+-----+---------+----------------+ 

的左聯接長,請求需要3秒,0,0158秒wihtout。

對每50行進行一次sql請求會更加迅速。

子查詢會更快嗎?如何使它與子查詢?

謝謝