2014-04-20 83 views
1

我的應用程序的一部分存在一個大問題。我使用的是SQLAlchemy和MySQL的組合,並且大部分的工作都很好,但是有一個癢會持續加載,有時甚至5-6分鐘,載入客戶列表。該表大約有3000行,這對於數據庫標準來說應該是相當小的,並且我在一個稍大的表格(25k行)上有一個簡單的連接。MySQL性能不佳

在SQL鍊金術查詢如下:

last_inv = db.session.query(Sales.id).order_by(Sales.invoice_date.desc()).filter(Customer.email == Sales.email).limit(1).correlate(Customer) 
results = db.session.query(Customer, last_inv.as_scalar()).filter_by(archive=0) 

原始SQL看起來是這樣的:

SELECT customer.id AS customer_id 
    , customer.first_name AS customer_first_name 
    , customer.middle_name AS customer_middle_name 
    , customer.last_name AS customer_last_name 
    , customer.email AS customer_email 
    , customer.password AS customer_password 
    , customer.address1 AS customer_address1 
    , customer.address2 AS customer_address2 
    , customer.city AS customer_city 
    , customer.state AS customer_state 
    , customer.zip AS customer_zip 
    , customer.country AS customer_country 
    , customer.phone AS customer_phone 
    , customer.cell_phone AS customer_cell_phone 
    , customer.current_plan AS customer_current_plan 
    , customer.minutes_current_plan AS customer_minutes_current_plan 
    , customer.orig_sales_id AS customer_orig_sales_id 
    , customer.sales_id AS customer_sales_id 
    , customer.team_id AS customer_team_id 
    , customer.refill_date AS customer_refill_date 
    , customer.minutes_refill_date AS customer_minutes_refill_date 
    , customer.active AS customer_active 
    , customer.archive AS customer_archive 
    , customer.imported AS customer_imported 
    , customer.ipaddress AS customer_ipaddress 
    , customer.auto_renewal AS customer_auto_renewal 
    , customer.signup_date AS customer_signup_date 
    , customer.esn AS customer_esn 
    , customer.last_update_date AS customer_last_update_date 
    , customer.last_update_by AS customer_last_update_by 
    , customer.notes AS customer_notes 
    , customer.current_pin AS customer_current_pin 
    , customer.minutes_current_pin AS customer_minutes_current_pin 
    , customer.security_pin AS customer_security_pin 
    , (SELECT sales.id 
      FROM sales 
     WHERE customer.email = sales.email 
     ORDER 
      BY sales.invoice_date DESC LIMIT 1) AS anon_1 
    FROM customer 
WHERE customer.team_id = 1 
    AND customer.archive = 0 

我已經試過無數的事情,但這是真的開始讓我感到絕望。這一切都在亞馬遜上運行,並且htop在運行時顯示100%的MySQL使用率。 Profiler對phpmyadmin進行查詢時,HeidiSQL顯示它在不到兩秒的時間內完成(當不在cahce中查找時),所以它不是實際的查詢造成的(正如我理解的那樣)。

這是EXPLAIN顯示:

從phpmyadmin的
id select_type table type possible_keys key key_len ref rows Extra 
1 PRIMARY customer ALL NULL NULL NULL NULL 3621 Using where 
2 DEPENDENT SUBQUERY sales ALL NULL NULL NULL NULL 22619 Using where; Using filesort 

Profiler是here和視覺表現here

我在EC2上運行一個m1.small實例,內存爲1650MB。

我也運行了一個mysqlprofiler,以下是結果beforeafter我所做的優化。我的my.cnf文件是here

我已經嘗試在表上運行OPTIMIZE,但由於某種原因未優化的表的數量總是98,所以我想我做錯了什麼。我使用this腳本,以及phpmyadmin中的原始sql,但沒有成功。

任何幫助表示讚賞,謝謝閱讀!

+0

相關的子查詢往往表現不佳 – Strawberry

+2

你有'customer.email'和'sales.email'上的索引嗎? – datasage

+0

我現在就做!第二個,sales.email沒有索引,完全忘了。哇現在顯着更快,謝謝一堆! :) –

回答

2

嘗試創建這個多列索引,這應該加快查詢更多:

CREATE INDEX sales_eml_invdat ON sales(email, invoice_date); 
上三列

CREATE INDEX sales_eml_invdat_id ON sales(email, invoice_date, id); 

但只有在一個情況下

甚至當id不是主鍵柱。
如果id是主鍵,那麼前一個索引就足夠了。

---- ------編輯

我很抱歉,我忘了MySQL是沒有那麼聰明的人DBMS。
它不能自己檢測到這種情況,必須明確告訴他如何去做。
請rewrtite子查詢到:

SELECT sales.id 
FROM sales 
WHERE customer.email = sales.email 
ORDER BY sales.email DESC, sales.invoice_date DESC 
LIMIT 1 

這種變化使MySQL使用(email, invoice_date)指數跳過文件排序,請試試吧。

+0

兩個索引,一個主鍵和一個常規索引,還是多列索引之間有區別?我已經將索引添加到電子郵件列... –

+0

是的,有一個區別,但這是一個巨大的話題。請閱讀以下鏈接:http://dev.mysql.com/doc/refman/5.7/en/range-optimization.html以及下面的鏈接:http://dev.mysql.com/doc/refman/5.7/en /order-by-optimization.html以瞭解mysql如何使用單列索引和多列索引。對於單一索引,MySql必須總是讀取'sales'表並執行一個filesort,使用多列索引它可以直接從索引中讀取所有需要的數據並跳過排序操作。 – krokodilko

+0

謝謝!我現在肯定,因爲我在那裏使用排序,在這種情況下多列應該更好,而將創建一個。 –