日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

mysql 更新时间加数字_Mysql实战45讲笔记:8、聚合函数count

發布時間:2023/12/2 数据库 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mysql 更新时间加数字_Mysql实战45讲笔记:8、聚合函数count 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

count(*)的實現方式

在不同的MySQL引擎中,count()有不同的實現方式 1. MyISAM引擎把一個表的總行數存在了磁盤上,因此執行count()的時候會直接返回這個數,效率很高; 2. 而InnoDB引擎就麻煩了,它執行count(*)的時候,需要把數據一行一行地從引擎里面讀出來,然后累積計數。

以上是沒有過濾條件的count(*),如果加了where 條件的話,MyISAM表也是不能返回得這么快的。

為什么InnoDB不跟MyISAM一樣,也把數字存起來呢?

因為即使是在同一個時刻的多個查詢,由

于多版本并發控制(MVCC)的原因,InnoDB表“應該返回多少行”也是不確定的

假設表t中現在有10000條記錄,我們設計了三個用戶并行的會話。

  • 會話A先啟動事務并查詢一次表的總行數;
  • 會話B啟動事務,插入一行后記錄后,查詢表的總行數
  • 會話C先啟動一個單獨的語句,插入一行記錄后,查詢表的總行數。

我們假設從上到下是按照時間順序執行的,同一行語句是在同一時刻執行的, 在最后一個時刻,三個會話A、B、C會同時查詢表t的總行數,但拿到的結果卻不同。

這和InnoDB的事務設計有關系,可重復讀是它默認的隔離級別,在代碼上就是通過多版本并發控制,也就是MVCC來實現的。每一行記錄都要判斷自己是否對這個會話可見,因此對于count(*)請求來說,InnoDB只好把數據一行一行地讀出依次判斷,可見的行才能夠用于計算“基于這個查詢”的表的總行數。

不過MySQL在執行count(*)操作的時候還是做了優化: MySQL優化器會找到最小的那棵樹來遍歷。在保證邏輯正確的前提下,盡量減少掃描的數據量,是數據庫系統設計的通用法則之一

小結: MyISAM表雖然count()很快,但是不支持事務; show table status命令雖然返回很快,但是不準確; InnoDB表直接count(*)會遍歷全表,雖然結果準確,但會導致性能問題。

用緩存系統保存計數

對于更新很頻繁的庫來說,可能會第一時間想到,用緩存系統來支持。 用一個Redis服務來保存這個表的總行數。這個表每被插入一行Redis計數就加1,每被刪除一行Redis計數就減1。這種方式下,讀和更新操作都很快,但是這種方式存在問題:可能會丟失更新

Redis的數據不能永久地留在內存里,所以會把這個值定期地持久化存儲起來。但即使這樣,仍然可能丟失更新。試想如果剛剛在數據表中插入了一行,Redis中保存的值也加了1,然后Redis異常重啟了,重啟后要從存儲redis數據的地方把這個值讀回來,而剛剛加1的這個計數操作卻丟失了。

雖然這個場景可以解決:在Redis異常重啟以后,到數據庫里面單獨執行一次count(*)獲取真實的行數,再把這個值寫回到Redis里。異常重啟畢竟不是經常出現的情況,這一次全表掃描的成本,還是可以接受的。 不過,將計數保存在緩存系統中的方式,還不只是丟失更新的問題。即使Redis正常工作,這個值還是邏輯上不精確的。

如果要顯示操作記錄的總數,同時還要顯示最近操作的100條記錄。那么,這個頁面的邏輯就需要先到Redis里面取出計數,再到數據表里面取數據記錄。

我們是這么定義不精確的:

  • 一種是,查到的100行結果里面有最新插入記錄,而Redis的計數里還沒加1;
  • 另一種是,查到的100行結果里沒有最新插入的記錄,而Redis的計數里已經加了1。

這兩種情況,都是邏輯不一致的。

在并發系統里面,無法精確控制不同線程的執行時刻的,因為存在圖中的這種操作序列,所以,即使Redis正常工作,這個計數值還是邏輯上不精確的。

在數據庫保存計數

如果我們把這個計數直接放到數據庫里單獨的一張計數表C中,又會怎么樣呢?

首先,這解決了崩潰丟失的問題,InnoDB是支持崩潰恢復不丟數據的。 其次,由于InnoDB是支持事務的,所以從下圖可以看出邏輯上是一致的

不同的count用法

count()是一個聚合函數,對于返回的結果集,一行行地判斷,如果count函數的參數不是NULL,累計值就加1,否則不加。最后返回累計值。
  • count(*)、count(主鍵id)和count(1) 都表示返回滿足條件的結果集的總行數;
  • count(字段),則表示返回滿足條件的數據行里面,參數“字段”不為NULL的總個數。
  • 對于count(主鍵id)來說:InnoDB引擎會遍歷整張表,把每一行的id值都取出來,返回給server層。server層拿到id后,判斷是不可能為空的,就按行累加。
  • 對于count(1)來說,InnoDB引擎遍歷整張表,但不取值。server層對于返回的每一行,放一個數字“1”進去,判斷是不可能為空的,按行累加。
單看這兩個用法的差別的話,你能對比出來,count(1)執行得要比count(主鍵id)快。因為從引擎返回id會涉及到解析數據行,以及拷貝字段值的操作。
  • 對于count(字段)來說:
  • 如果這個“字段”是定義為not null的話,一行行地從記錄里面讀出這個字段,判斷不能為null,按行累加;
  • 如果這個“字段”定義允許為null,那么執行的時候,判斷到有可能是null,還要把值取出來再判斷一下,不是null才累加。
  • count(*)是例外,并不會把全部字段取出來,而是專門做了優化,不取值。count(*)肯定不是null,按行累加。
  • 按照效率排序的話,count(字段)<count(主鍵id)<count(1)≈count(*),建議盡量使用count(*)。

    總結

    以上是生活随笔為你收集整理的mysql 更新时间加数字_Mysql实战45讲笔记:8、聚合函数count的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。