背景
近期為了保障線上數(shù)據(jù)庫的穩(wěn)定性澡刹,我決定針對一些大表的歷史數(shù)據(jù)有計劃地進行備份遷移呻征,但是呢,發(fā)現(xiàn)一個奇特的現(xiàn)象罢浇,Navicat統(tǒng)計行數(shù)和表自身count統(tǒng)計數(shù)竟然不一致B礁场?0.0
Navicat
Navicat作為數(shù)據(jù)庫管理工具嚷闭,在業(yè)界廣受歡迎攒岛,先甭管你電腦上現(xiàn)在正在運行的Navicat是正版還是盜版(你不說我也知道),不可否認的是胞锰,在我從事17年從事后端開發(fā)以來灾锯,嘗試了很多同類工具,Navicat在功能上完全碾壓其他數(shù)據(jù)庫管理工具嗅榕,尤其是細節(jié)方面顺饮,在這里不一一列舉了吵聪,總之一個字,就是很好用(不接受反駁兼雄,除非你說出來一個讓我心服口服的工具)吟逝。
整個經(jīng)過
這次大表遷移備份,我的整體思路是:首先用Navicat對庫內(nèi)所有的表按照行數(shù)降序排序君旦,然后選取Top10進行遷移備份澎办。但是一如既往細心的我發(fā)現(xiàn),它界面的統(tǒng)計行數(shù)竟然和我自己count這張表行數(shù)不一致金砍?局蚀!難道要顛覆我對Navicat的認可嘛。
select count(1) from big_table_name;
為什么呢恕稠?
這讓我很是詫異琅绅,一度以為自己出現(xiàn)了幻覺,再三確認自己沒有帶VR眼鏡后鹅巍,我踏上了尋找答案的征程千扶。我開始思考,Mysql作為一個數(shù)據(jù)庫骆捧,自身肯定就有各個表的統(tǒng)計澎羞,而Navicat只是作為一個可視化界面,讓數(shù)據(jù)肉眼可見敛苇。
Navicat:這鍋我可不背妆绞。
為了證實我的猜想,我查閱了官方文檔及其他相關(guān)資料枫攀,果然括饶,MySQL 在 information_schema.TABLES
表中息存放了所有表的信息。
select * from information_schema.TABLES;
查看了這張表以后来涨,發(fā)現(xiàn)表里統(tǒng)計記錄TABLE_ROWS
字段的確實與事實count不符……
這又是為什么呢图焰?
我又陷入了沉思,帶著疑惑蹦掐,繼續(xù)翻閱著文檔技羔,突然,看到MySQL官方文檔對TABLE_ROWS
的解釋:
The number of rows. Some storage engines, such as MyISAM, store the exact count. For other storage engines, such as InnoDB, this value is an approximation, and may vary from the actual value by as much as 40% to 50%. In such cases, use SELECT COUNT(*) to obtain an accurate count.
看了這段話我頓悟啦卧抗,你是不是也明白怎么回事啦藤滥。什么?你沒看太明白颗味?好吧,沒關(guān)系牺弹,你可能需要通過翻譯軟件的直譯+理解浦马,才懂得其中真正的含義时呀。原來,TABLE_ROWS
這個字段不同存儲引擎的計數(shù)規(guī)則不一致晶默,比如MyISAM引擎這表存儲TABLE_ROWS
存儲的就是精確的行數(shù)谨娜,而對于其他的存儲引擎,比如 InnoDB磺陡,這個值只是一個近似值趴梢,與實際值相差40%-50%左右。所以币他,在這種情況下坞靶,我們想要得到一個準(zhǔn)確的計數(shù),只能使用 SELECT COUNT(*) 來獲得蝴悉。
那又如何修正呢彰阴?
雖然疑惑得到了解答。但拍冠,和我一樣有強迫癥的朋友肯定會問尿这,如何修正這個值呢?真是知道越多庆杜,未知越多射众,網(wǎng)上說可以通過
Analyze table big_table_name
得以更正這個數(shù)據(jù),但是我動手執(zhí)行之后發(fā)現(xiàn)晃财,并不能更正數(shù)據(jù)叨橱,且該操作不僅耗時還會鎖表,并不推薦使用……說到這拓劝,我的強迫癥竟然不治自愈了雏逾。
朋友,你有更好的辦法嘛郑临?歡迎留言栖博。
本文可轉(zhuǎn)載,但需聲明原文出處厢洞。 程序員小明仇让,一個很少加班的程序員。歡迎關(guān)注微信公眾號“程序員小明”躺翻,獲取更多優(yōu)質(zhì)文章丧叽。