2012-03-12 76 views
0
SELECT citing.article_id as citing, lac_a.year, r.id_when_cited, cited_issue.country, citing.num_citations 
FROM isi_lac_authored_articles as lac_a 
    JOIN isi_articles citing ON (lac_a.article_id = citing.article_id) 
    JOIN isi_citation_references r ON (citing.article_id = r.article_id) 
    JOIN isi_articles cited ON (cited.id_when_cited = r.id_when_cited) 
    JOIN isi_issues cited_issue ON (cited.issue_id = cited_issue.issue_id); 

我有所有被加入的領域的索引。如何優化多個連接(已經有索引)的查詢?

有什麼我可以做的嗎?我的表很大(大約有100萬條記錄,參考表有5億條記錄,文章表有25萬條記錄)。

這就是EXPLAIN不得不說:

+----+-------------+-------------+--------+--------------------------------------------------------------------------+---------------------------------------+---------+-------------------------------+---------+-------------+ 
| id | select_type | table  | type | possible_keys               | key         | key_len | ref       | rows | Extra  | 
+----+-------------+-------------+--------+--------------------------------------------------------------------------+---------------------------------------+---------+-------------------------------+---------+-------------+ 
| 1 | SIMPLE  | cited_issue | ALL | NULL                  | NULL         | NULL | NULL       | 1156856 |    | 
| 1 | SIMPLE  | cited  | ref | isi_articles_id_when_cited,isi_articles_issue_id       | isi_articles_issue_id     | 49  | func       |  19 | Using where | 
| 1 | SIMPLE  | r   | ref | isi_citation_references_article_id,isi_citation_references_id_when_cited | isi_citation_references_id_when_cited | 17  | mimir_dev.cited.id_when_cited |  4 | Using where | 
| 1 | SIMPLE  | lac_a  | eq_ref | PRIMARY                 | PRIMARY        | 16  | mimir_dev.r.article_id  |  1 |    | 
| 1 | SIMPLE  | citing  | eq_ref | PRIMARY                 | PRIMARY        | 16  | mimir_dev.r.article_id  |  1 |    | 
+----+-------------+-------------+--------+--------------------------------------------------------------------------+---------------------------------------+---------+-------------------------------+---------+-------------+ 
5 rows in set (0.07 sec) 
+0

編輯:增加說明輸出 – pocketfullofcheese 2012-03-12 07:52:00

+1

你使用什麼數據庫類型?這是一個非常簡單的SQL語句。你在使用myisam還是innodb? – 2012-03-12 07:57:28

+0

myisam。它簡單的SQL,但表格很大。 EXPLAIN輸出的第一行有1M行...我可以通過分割我的查詢來避免這種類型的事情嗎?或者是其他東西? – pocketfullofcheese 2012-03-12 08:01:08

回答

0

如果你真的需要所有返回的數據,我建議兩兩件事:

  1. 你,大概,知道數據比MySQL更好,你可以嘗試利用它的優勢,如果MySQL是不正確在其假設中。目前,MySQL認爲在開始時更容易全面掃描整個isi_issues表,並且如果結果真的會包含所有問題,那麼假設是正確的。但是,如果結果中不存在許多問題,則可能需要強制您認爲更加正確的另一個連接順序。這是你,誰知道哪個表應用最強的限制,哪些是最小的到完全掃描(因爲沒有WHERE子句,你無論如何都需要全面掃描一些東西)。

  2. 您可以通過覆蓋索引(即包含足夠數據本身且不需要觸摸行數據的索引)獲利。例如,isi_articles和(article_id,year)isi_lac_authored_articles上的索引(article_id,num_citations)和isi_issues上的(國家)將會顯着加快該查詢,只要索引適合內存,但從另一方面來看,會讓你的索引變大並且稍微慢一點的插入到表中。

+0

在第1點。我知道它不會被使用所有問題。我如何強制它最後加入JOIN?我想要全面掃描的唯一表格是第一個(isi_lac_authored_articles)。 – pocketfullofcheese 2012-03-12 16:07:58

+0

@pocketfullofcheese,看看在MySQL文檔中的'STRAIGHT_JOIN':http://dev.mysql.com/doc/refman/5.1/en/select.html – newtover 2012-03-12 16:12:30

+0

我試過了,但它似乎並沒有正在變得更快。我如何檢查發生了什麼?有沒有辦法檢查查詢的進度? – pocketfullofcheese 2012-03-12 23:18:13

0

我認爲這是你能做的最好的。我的意思是至少它沒有使用嵌套/多個查詢。你應該在sql上做一點基準。你至少可以儘可能地限制你的結果。 15-30行的返回設置是非常好的每頁(這取決於應用程序,但15-30對我來說是公差範圍)

我相信mySQL(phpMyAdmin,控制檯,GUI無論)他們返回一些排序「執行時間」,即執行查詢所花費的時間。將其與使用服務器端代碼的查詢基準進行比較。然後將其與使用服務器端代碼運行的查詢進行比較,然後將其與您的應用程序界面一起輸出。

通過這個,你可以看到你的瓶頸在哪裏 - 這是你優化的地方。

+0

我只是運行這個服務器端,它的數據分析。但我需要多次運行它(具有不同的變化)。問題是,查詢需要數小時。但是我不確定哪部分需要這麼長時間,或者我可以做些什麼來加速它(例如,將它分成多個查詢並將結果保存在臨時表中) – pocketfullofcheese 2012-03-12 07:51:47

+0

如果這是您唯一的查詢,我建議分批進行測試,例如每次少數測試,並檢查執行所需的時間。此查詢返回多少行?這個問題可能是因爲你只是有一堆巨大的數據,並且每個查詢返回大量的結果。 – Joseph 2012-03-12 08:00:44

+0

是的,它將返回3M行。我需要耐心嗎? – pocketfullofcheese 2012-03-12 08:02:30

0

除非將查詢結果輸入到某個其他查詢或系統,否則返回那麼多(3M)行是沒用的。每個查詢返回一個可接受數量的行(比如1000)用於可視化會很聰明。

0

看你的SQL - 缺乏一個WHERE子句意味着它是由拉的所有行:

JOIN isi_issues cited_issue ON (cited.issue_id = cited_issue.issue_id) 

你可以看看分割大isi_issues表,這將讓MySQL的執行有點快(更小的文件更容易處理)

或者,您也可以循環語句並使用LIMIT子句。

LIMIT 0,100000 然後 LIMIT 100001,200000

這將讓報表運行更快,你可以處理批量數據。

+0

我不這麼認爲,在這裏使用'LIMIT'是一個好主意,因爲要輸出100001行,200000 MySQL需要重新讀取第0,1,0000行。 – newtover 2012-03-12 09:41:44