2011-02-23 153 views
3

我有一個包含超過50M行的幾個表的MySQL 5.0數據庫。但我怎麼知道這一點?當然,通過運行「SELECT COUNT(1)FROM foo」。包含58.8M行的一個表上的這個查詢需要10分鐘才能完成!在MySQL 5中,SELECT COUNT(1)FROM table_name非常慢

mysql> SELECT COUNT(1) FROM large_table; 
+----------+ 
| count(1) | 
+----------+ 
| 58778494 | 
+----------+ 
1 row in set (10 min 23.88 sec) 

mysql> EXPLAIN SELECT COUNT(1) FROM large_table; 
+----+-------------+-------------------+-------+---------------+----------------------------------------+---------+------+-----------+-------------+ 
| id | select_type | table    | type | possible_keys | key         | key_len | ref | rows  | Extra  | 
+----+-------------+-------------------+-------+---------------+----------------------------------------+---------+------+-----------+-------------+ 
| 1 | SIMPLE  | large_table  | index | NULL   | fk_large_table_other_table_id   | 5  | NULL | 167567567 | Using index | 
+----+-------------+-------------------+-------+---------------+----------------------------------------+---------+------+-----------+-------------+ 
1 row in set (0.00 sec) 

mysql> DESC large_table; 
+-------------------+---------------------+------+-----+---------+----------------+ 
| Field    | Type    | Null | Key | Default | Extra   | 
+-------------------+---------------------+------+-----+---------+----------------+ 
| id    | bigint(20) unsigned | NO | PRI | NULL | auto_increment | 
| created_on  | datetime   | YES |  | NULL |    | 
| updated_on  | datetime   | YES |  | NULL |    | 
| other_table_id | int(11)    | YES | MUL | NULL |    | 
| parent_id   | bigint(20) unsigned | YES | MUL | NULL |    | 
| name    | varchar(255)  | YES |  | NULL |    | 
| property_type  | varchar(64)   | YES |  | NULL |    | 
+-------------------+---------------------+------+-----+---------+----------------+ 
7 rows in set (0.00 sec) 

所有問題的表都是InnoDB。

任何想法,爲什麼這是如此緩慢,我如何加快速度?

+0

的手冊。也許您應該發佈「SHOW CREATE TABLE」的輸出並給我們一些關於您的問題域的背景信息? – MarkR

+0

馬克,在這種情況下,問題域並不重要,因爲我所要做的就是對行進行計數。 :) –

回答

2

如果你需要有結果立刻和你不在乎它是否58.8M或51.7M,您可以通過調用

show table status like 'large_table'; 

找出行的大致數量見列rows
有關結果的更多信息,請參見http://dev.mysql.com/doc/refman/5.1/en/show-table-status.html

+0

這個信息也在INFORMATION_SCHEMA中可用。但結果是「有點隨意」。 – MarkR

+0

近似值是爲我的使用情況找到的。我只需要縮放計算的信息,實際上只需要在一個數量級內準確。由於我不是添加或刪除一個數量級的行,我不必擔心輕微的模糊性。 –

-2

select count(id) from large_table一定會跑得更快

+0

是什麼讓你覺得呢?在InnoDB上進行PK索引掃描比通常進行二級索引掃描要糟糕(因爲數據是集羣化的,所以條目通常更大,因此每頁更少,因此IO操作更多)。 – MarkR

+0

COUNT(id)永遠不可能是比COUNT(1)快。無論何時計算行項目並使用*或列名稱,內部機制將檢查行中的第一個非NULL列(使用COUNT(*)時)或檢查括號中指定的列(當使用COUNT(id) )通過使用COUNT(1)可以繞過該機制,因爲1是一個總是相同的標量數,因此一行中的表列不會被加載和檢查。當我在Oracle8i Cert學習指南的第78頁上閱讀這篇文章時,我從Oracle開發者日獲悉了這一點。正如@MarkR之前開始的那樣,MVCC只是擋道而已。 – RolandoMySQLDBA

+0

無論如何,COUNT(some_non_null_column)應該與COUNT(1)或實際上COUNT(*)相同。如果優化器以不同的方式處理它們,則會被打破。 – MarkR

6

計數表中的所有行是一個非常緩慢的操作;除非您準備在其他地方進行計數(當然,這可能會失去同步),否則您無法真正加快速度。

習慣了MyISAM的人往往認爲他們可以免費得到數(*),但它並不是真的。 MyISAM通過沒有MVCC作弊,這使得它相當容易。

您顯示的查詢是對非空索引執行完整索引掃描,這通常是對innodb表中的行進行計數的最快方法。

很難從您提供的信息中猜出您的應用程序是什麼,但一般來說,用戶(等)可以看到大表中行數近似的近似值。

+0

這裏有一些解釋:http://www.mysqlperformanceblog.com/2006/12/01/count-for-innodb-tables/ –

相關問題