2010-06-28 86 views
5

以下查詢有效,但對於10條記錄(2秒)非常緩慢。分析表明它創建了一個tmp表,但我不知道爲什麼。MySQL - 如何優化此查詢?

基本上,我加入當前用戶,加入acl團隊,獲得他們所在的所有團體,然後將團隊加入公司,獲得他們所在的所有公司,然後加入公司以接受訂單,讓所有的訂單..

如果我刪除此行

ORDER BY orders.created_on DESC 

那麼查詢在0.06秒執行(更然後可以接受的)..

幫助,就如何優化的任何想法?非常感謝:)

SELECT 
    orders.uuid, 
    companies.name as company_name 
FROM 
    users u 
JOIN  
    users_acl_groups g on u.uuid = g.user_uuid 
JOIN 
    users_acl acl on (acl.user_uuid = u.uuid or acl.group_uuid = g.group_uuid) 
JOIN 
    companies on acl.item_uuid = companies.uuid 
JOIN 
    orders on companies.uuid = orders.company_uuid 
WHERE 
    u.uuid = 'DDEC8073-5056-C000-01ED583A51CBCA32' and orders.status <> '' 
ORDER BY orders.created_on DESC 

limit 0, 10; 

UPDATE時,查詢的解釋..

1簡單的命令ALL 9403使用 臨時的;使用filesort

1 SIMPLE acl ALL 1859使用where; 使用加入緩衝區

1 SIMPLE g ALL 2005 Using where; 使用連接緩衝

1家SIMPLE公司eq_ref PRIMARY PRIMARY 52 table.orders.company_uuid 1

1個簡單U ALL 33595使用其中; 不同的;使用連接緩衝

+0

修改了您的標題,因爲猜測當您的問題的措辭很好時,由於它的命令性和要求苛刻的語氣會導致成本降低。 – 2010-06-28 05:18:35

+0

嘗試使用相同查詢並將聯接應用於UID以外的任何列。嘗試使用int,float,string,UID並注意時間。讓我們也知道,如果你發現任何變化。 – 2010-06-28 12:36:56

+0

你有關於orders.created_on的索引嗎?在查詢中顯示'EXPLAIN'上的輸出。也許你可以從其他指標中受益。哪個'EXPLAIN'會告訴我們。 – nos 2010-06-28 13:04:56

回答

2

你有沒有考慮製作事實表風格的設計,作爲非規範化的步驟?

基本上它是一種多到許多交叉點表,例如:

CREATE TABLE user_order_fact (
    user_uuid ... 
    order_uuid ... 
    order_created_on ... 
    order_status ... 
    company_name ..., 
    primary key (user_uuid, order_uuid), 
    key (user_uuid, order_status, order_created_on, order_uuid, company_name) 
); 

... fill with data ... 

SELECT 
    order_uuid, 
    company_name 
FROM 
    user_order_fact 
WHERE 
    user_uuid = 'DDEC8073-5056-C000-01ED583A51CBCA32' and order_status <> '' 
ORDER BY order_created_on DESC 

limit 0, 10; 

我猜測的複合索引。你必須嘗試,直到你做對了。基本上你試圖讓優化器計劃報告它是使用索引

當然,這是以非規範化的形式冗餘存儲數據,所以你需要設置一些觸發器來保持它與規範化表同步。

+0

嗯,也許PK只是order_uuid。我不保證這是最好的設計,只是試圖讓你瞭解我的意思。 – 2010-06-28 05:34:20

0

確保「orders.created_on」有一個索引......如果是,那麼比爾在頂端的方法將是最好的,但需要一些工作。

+0

我認爲它呢? KEY'created_on'('created_on') – Brett 2010-06-28 05:32:39

0

如果不瞭解現有索引或每張表的容量,很難回答。

此外,沒有關於模型的許多信息......查詢是否返回所有結果?

是否所有用戶都屬於一個組?看起來不是......並且查詢不會返回組外的用戶。

一個組是否可以屬於一個組,調用遞歸查詢?

+0

我正在嘗試將遞歸查詢的事情做出來,但我沒有太多的運氣:(表格很安靜,10,000條記錄全部存在。目前沒有索引.. – Brett 2010-06-28 08:29:51

+0

@Brett:如果在這種情況下存在索引將不起作用,因爲NOT運算符和Like運算符不使用索引 – 2010-06-28 12:35:36

0

我不確定什麼可能是它需要2秒的確切原因。這是不可能的這個查詢獲取10條記錄,但什麼是在這裏看到的是基於

  1. acl.user_uuid = u.uuid or acl.group_uuid = g.group_uuid

    UID加入,可能你也是 使用它作爲一個主鍵 上述回答。

  2. ORDER BY orders.created_on。在date上使用Order by將不會比使用PK更優,或者任何整數值 更合適。

  3. orders.status <> ''如果使用則沒有索引 可以在此查詢中使用表上的任何索引,因爲 不是運營商和像 運營商不以任何查詢時使用索引。

  4. 表中存在的記錄數量可能是另一個原因,但僅限於以上因素。否則,它也可能處理大量。

重大,我認爲是在使用UID加入 因此,所有這三個避免的條件可以在查詢中可以看出,可能使你的查詢懶

+0

嗨,謝謝您的迴應。第2條中的最小化是什麼意思? – Brett 2010-06-28 11:16:00

0

一些想法促成因素:

您實際上未在您的查詢中選擇orders.created_on。所以在這個專欄上排序沒有意義。也許,選擇它(SELECT orders.created_on ...)將有助於表現(只是瘋狂的猜測 - 我不知道我在說什麼)。

您可以隨時在您的應用程序中進行排序 - 如果查詢返回的記錄數量不是很多。

有時,使用N個小型查詢而不是1個大型SQL查詢會更具性能。僞代碼:

user_id = get_one("SELECT uuid FROM users WHERE ..."); 
group_ids = get_many("SELECT uuid FROM groups WHERE user_uuid = " + user_id); 
comps_ids = get_many("SELECT DISTINCT item_uuid FROM acls WHERE user_uuid = " + user_id + " OR group_uuid IN " + groups_ids.to_q()); 
orders = get_many("SELECT * FROM orders WHERE company_uuid IN " + comps_ids.as_q() + " WHERE status <> '' ORDER BY created_on");