如果在 MySQL 中使用了 InnoDB 引擎,那么對(duì)于常規(guī)的 COUNT (id) 等操作非常耗費(fèi)資源,速度比較慢,為了保持效率,需要將這些數(shù)據(jù)行的統(tǒng)計(jì)值保存起來(lái),使用的時(shí)候直接查詢獲取就可以了。比如一個(gè) BBS 系統(tǒng)中需要將每個(gè)論壇板塊的主題數(shù)量和回復(fù)數(shù)量作為一個(gè)字段保存到相應(yīng)的板塊信息表中;如果主題和回復(fù)變動(dòng)不頻繁,那么對(duì)這個(gè)統(tǒng)計(jì)值的操作也不頻繁,每次使用 COUNT (id) 重新查詢還是可行的,但如果面對(duì)的是一個(gè)大型 BBS,不僅數(shù)據(jù)量巨大,而且用戶數(shù)巨大引起主題和回復(fù)更新非???,頻繁的對(duì)巨量數(shù)據(jù)調(diào)用 COUNT (id) 查詢,在性能上是不太現(xiàn)實(shí)的;所以,對(duì)于頻繁更新的統(tǒng)計(jì)值,我們可以采用另外一種方法:直接加減。也就是說(shuō),如果增加了新主題,針對(duì)主題的統(tǒng)計(jì)值進(jìn)行加一操作,反過(guò)來(lái),刪除主題,進(jìn)行減一操作。
在 實(shí)際使用加減法更新統(tǒng)計(jì)值的時(shí)候,總有可能會(huì)發(fā)生統(tǒng)計(jì)值不正確的時(shí)候,特別是當(dāng)統(tǒng)計(jì)值已經(jīng)是零的時(shí)候如果再次減一,就會(huì)變成無(wú)法接受的錯(cuò)誤:負(fù)值;如果你 將統(tǒng)計(jì)值字段定義了 unsigned,-1 會(huì)變成該字段的最大值(二進(jìn)制取反引起的),也是無(wú)法接受的。這個(gè)時(shí)候,我們需要一個(gè) SQL 函數(shù),實(shí)現(xiàn)類似編程語(yǔ)言中 Max() 函數(shù)的功能,將這個(gè)統(tǒng)計(jì)值最小控制在 0。
在 PostgreSQL 中,有一個(gè)叫 greatest 的條件函數(shù),可以讓我們通過(guò)以下 SQL 語(yǔ)句避免統(tǒng)計(jì)值出現(xiàn)負(fù)值:
UPDATE dd_stml_stat SET stat_value=GREATEST(stat_value-1,0) WHERE stat_id=10;
可惜的是,在 MySQL 中并沒(méi)有對(duì)應(yīng)的函數(shù),不過(guò) MySQL 有一個(gè)叫 IF() 的特殊 Control Flow Function,可以使用它來(lái)實(shí)現(xiàn)我們的目標(biāo):
UPDATE dd_stml_stat SET stat_value=(IF(stat_value>1,stat_value-1,0)) WHERE stat_id=10;
其實(shí)這個(gè) IF() 函數(shù)就是一個(gè)簡(jiǎn)單的判斷器,它會(huì)判斷第一個(gè)參數(shù)是否成立,如果是 True,就會(huì)返回第二個(gè)表達(dá)式的值,如果是 False,會(huì)返回第三個(gè)表達(dá)式的值;從而變相的在 MySQL 中實(shí)現(xiàn)了大小值比對(duì)函數(shù)。