2009-06-30 71 views
5

此SQL查詢令我厭惡。我沒有寫它,但這是我們服務器上的一個大問題。我願意將它分成多個查詢,並通過PHP進行一些處理(如RAND())。優化此SQL查詢

$sql = "SELECT a.code, a.ad_id, a.position, a.type, a.image, a.url, a.height, a.width 
    FROM " . AD_TABLE ." a, " . USER_GROUP_TABLE . " g 
    WHERE (a.max_views >= a.views OR a.max_views = '0') 
    AND (FIND_IN_SET(" .$forum_id. ", a.show_forums) > 0 OR a.show_all_forums = '1') 
    AND g.user_id = " . $user->data['user_id'] . " 
    AND FIND_IN_SET(g.group_id, a.groups) 
    AND FIND_IN_SET(" . $user->data['user_rank'] . ", a.ranks) 
    AND a.start_time < " . time() . " 
    AND a.end_time > " . time() . " 
    AND (a.clicks <= a.max_clicks OR a.max_clicks = '0') 
    ORDER BY rand()"; 

Yeesh,我覺得噁心粘貼,經過...

編輯:下面是對上面的格式樣本查詢「解釋」的結果,逗號分隔:

"id","select_type","table","type","possible_keys","key","key_len","ref","rows","Extra" 
1,"SIMPLE","g","ref","user_id","user_id","3","const",6,"Using temporary; Using filesort" 
1,"SIMPLE","a","ALL","max_views","","","",10,"Using where" 

這是

+2

你問的問題,或試圖獲得一些SQL優化而不付錢? – Mathew 2009-06-30 14:31:30

+0

你介意做一個EXPLAIN SELECT併發布結果嗎? – alexn 2009-06-30 14:34:59

回答

6

你這裏有三個主要問題:

  1. FIND_IN_SET

    它不可靠,索引不能使它更快。創建一個多對多關係表(或多個表)。

    • a.start_time < GETDATE() AND a.end_time > GETDATE()

    MySQL不優化好。你可以讓你的時間跨度爲幾何框,創建一個SPATIAL INDEX過他們,這會快很多(雖然少可讀)

    • ORDER BY RAND()

    如果您正在使用這個採樣數據(即你不「T需要的所有行,而是一個小隨機子集),有做這更有效的方式,在這篇文章中在我的博客中描述:

1

我猜你的問題在於日期。

AND a.start_time < " . time() . " 
AND a.end_time > " . time() . " 

我會嘗試把這些字段上的索引,看看是否有幫助。比較日期會導致數據庫與表中的每一行進行比較。

4
  • 沒有在表一和表G之間的查詢顯式連接:他們只能通過FIND_IN_SET(g.group_id,a.groups)
  • 多大的相關在「a.groups」中設置,即csv字符串是否包含大部分時間的一個組ID?
  • 如果99%的案例只包含1個組,則在php中對「a.groups」進行foreach循環,並從查詢中執行真正的連接(或可能完全消除您的user_group_table)。
    • 對於少數情況下您擁有多個組成員身份的情況,查詢仍然會通過顯式連接執行OK。

這將在你的PHP類/函數添加一些更多的代碼。

0

如果執行此了很多..嘗試和使用綁定變量(而不是字符串連接)..所以查詢沒有每一次被解析..

編輯:Sorry..didn」 t看到MYSQL標籤。除非最近發生變化,否則我不認爲MySQL喜歡準備好的語句。另一方面,ORACLE愛好它們。