MySQL - 使用 count(*) 和 information_schema.tables 計算行數的區別
我想要一種快速的方法來計算我的表中有幾百萬行的行數。我在 Stack Overflow 上找到了“ MySQL: Fastest way to count of rows ”的文章,看起來它可以解決我的問題。Bayuah提供了這個答案:
SELECT table_rows "Rows Count" FROM information_schema.tables WHERE table_name="Table_Name" AND table_schema="Database_Name";
我喜歡它,因為它看起來像查找而不是掃描,所以它應該很快,但我決定測試它
SELECT COUNT(*) FROM table
看看有多少性能差異。
不幸的是,我得到了不同的答案,如下所示:
題
為什麼答案相差大約 200 萬行?我猜測執行全表掃描的查詢是更準確的數字,但是有沒有辦法我可以得到正確的數字而不必執行這個慢查詢?
我跑了
ANALYZE TABLE data_302
,它在 0.05 秒內完成。當我再次執行查詢時,我現在得到了更接近 34384599 行的結果,但它仍然select count(*)
與 34906061 行的數字不同。分析表是否立即返回並在後台處理?我覺得值得一提的是,這是一個測試數據庫,目前沒有被寫入。沒有人會關心這是否只是告訴某人表有多大的情況,但我想將行數傳遞給一些程式碼,該程式碼將使用該數字創建一個“大小相等”的非同步查詢來查詢數據庫並行,類似於Alexander Rubin 在通過並行查詢執行提高慢速查詢性能中所示的方法。事實上,我只會得到最高的 id,
SELECT id from table_name order by id DESC limit 1
並希望我的表不會太分散。
有多種方法可以“計算”表中的行數。什麼是最好的取決於要求(計數的準確性,執行頻率,我們是否需要整個表的計數或變數
where
和group by
子句等)
- **a)**正常方式。數一數。
select count(*) as table_rows from table_name ;
準確度:執行查詢時 100% 準確計數。
效率:不適合大桌子。(對於 MyISAM 表非常快,但現在沒有人使用 MyISAM,因為它比 InnoDB 有很多缺點。*“驚人的快”*也僅適用於計算整個 MyISAM 表的行時 - 如果查詢
WHERE
有條件,它仍然必須掃描表或索引。)對於 InnoDB 表,它取決於表的大小,因為引擎必須掃描整個表或整個索引才能獲得準確的計數。表越大,速度越慢。
- **b)使用
SQL_CALC_FOUND_ROWS
**和FOUND_ROWS()
。如果我們還想要少量的行(更改LIMIT
),可以使用而不是以前的方式。我已經看到它用於分頁(獲取一些行,同時知道總共有多少行併計算 pgegs 的數量)。select sql_calc_found_rows * from table_name limit 0 ; select found_rows() as table_rows ;
準確度:同上。
效率:同上。
- **c)使用
information_schema
**表格作為連結問題:select table_rows from information_schema.tables where table_schema = 'database_name' and table_name = 'table_name' ;
準確度:只是一個近似值。如果表是頻繁插入和刪除的目標,則結果可能與實際計數相差甚遠。這可以通過
ANALYZE TABLE
更頻繁地執行來改善。效率:非常好,完全不碰桌子。
- d)將計數儲存在數據庫中(在另一個“計數器”表中)並在表每次插入、刪除或截斷時更新該值(這可以通過觸發器或通過修改插入和刪除過程來實現) .
這當然會在每個插入和刪除中增加額外的負載,但會提供準確的計數。
準確度:100% 準確計數。
效率:非常好,只需要從另一個表中讀取一行。
然而,它給數據庫帶來了額外的負載。
- **e)**在應用層儲存(記憶體)計數 - 並使用第一種方法(或先前方法的組合)。範例:每 10 分鐘執行一次精確計數查詢。在兩次計數之間的平均時間內,使用記憶體的值。
準確性:近似值,但在正常情況下還不錯(除非添加或刪除數千行)。
效率:非常好,價值始終可用。