話說畢業后做過幾年系統,對數據庫也就是增刪改查的水平,后來做的工作大多也沒有對數據庫深入使用,對數據庫的學習確實比較松懈,真是對不起自己在這個行業摸爬這么多年的經歷。昨天前對timestamp這個數據庫類型的理解,僅限於日常見到最多的Oracle的timestamp的用法,一個毫秒級的時間戳(這里其實是自己的認識上的誤區,其實人家的精度能做到納米級別)。然后我的好兄弟一下刷新了我對他的仰慕,填補了我多年的知識缺陷和空白(我們要不要在一起啊。。。在一起啊。。。)。在SQLServer中,這個值居然由SQLServer自行維護並且能隨着insert和update自動更新,而且這個字段存儲的和時間也毫無關系,只是一個順序遞增的binary值。
言歸正傳,先說說我遇到的問題。假設現在有兩個數據庫表,A和B,A是數據源,提供數據,每隔十分鍾會insert進一批數據。B是目標。另外有個SQL語句需要每隔十分鍾將A表的數據復制到B表,每次只復制增量。對於這種需求,我最喜歡的做法是insert into select * from xxx的語法了,這里唯一的問題就是如何區別出增量的問題。
假設這個表有一個自增列,1-1000000000000,那么我每次只需要記錄下上一次完成到哪一個就完事兒了。但是這里有諸多歷史問題導致了這個方案只能想想就罷了。因為A不是我的,B也不是我的,我就是那個insert into……,好吧,這是一個合作的項目,我對A和B的掌控能力和理解深度都不太深。而且這樣還有一個問題,自增列只會自增,一旦生成是不會更新的,當數據發生變化的時候,我們認為這些數據也是需要被同步的,那么update其實我們也需要。
原來我們工程師給出來的方案中無法避免的一個問題是它使用了>時間1 and <=時間2,當時間2這個時間點,有多條記錄被insert的話(相同時間),那么在表A被insert,而同步語句又在執行的時候,是有很高的幾率導致時間2這個時間點的數據記錄只被部分傳輸。而下一次同步的時候,時間2已然變成時間1,而大於號將導致丟失的數據再也補不回來。(假設是>= and <=,將導致時間2這個時間點的數據重復)
如果能解決時間2這個時間點的數據只有1條,這個問題就迎刃而解了。那么對於SQLServer而言,timestamp這個數據類型,就是我們要的(雖然官方文檔
https://msdn.microsoft.com/zh-cn/library/ms182776.aspx告訴我們,建議我們使用rowversion,但是在SQLServer2008R2的版本上,我沒有成功,貌似這個類型不支持,這個回頭再深究)。
那么我們還有Oracle、MySQL、PostgreSQL……OMZ……
簡單地搜了一下,結論大致如下(有不對的請大家及時指正)
1、Oracle的timestamp,是一個納秒級的時間,僅此而已,無法保證唯一性。而Oracle中也沒有類似的數據類型能夠直接做這件事。
這里有一點需要說明一下,Oracle的timestamp的默認時間精度是微秒(p=6),而Oracle能記錄到(p=9)也就是納秒。
可以參考:http://docs.oracle.com/cd/B19306_01/server.102/b14225/ch4datetime.htm#i1006050
但是有網友反映無論如何插入數據后再返回,只能取到微秒,后面3位總是0。網友的回復是這樣的:
ORACLE的timestamp可精確到9位,但ORACLE取時間的函數也是調用OS的取時間函數,而LINUX只能精確到6位,所以也只能如此了。這個在O'REILLY出版的《ORACLE PL/SQL程序設計》中有說明。
原文鏈接:http://www.itpub.net/forum.php?mod=viewthread&tid=1931266&extra=&highlight=&page=4
2、MySQL的timestamp,和SQLServer類似,但是也很不相同,首先它能自動設置,不需要人工干預,自動設置為當前時間(這一點和SQLServer 不一樣,SQLServer設置的是一個時間無關的二進制值,而這個設置的只是一個時間。)也就是說,它還會重復。而且,非常遺憾的是,這個時間還是個秒級的!同時,MySQL中也沒有類似的數據類型能夠直接做這件事。
可以參考:
http://www.jb51.net/article/51794.htm
http://dev.mysql.com/doc/refman/5.5/en/datetime.html
http://dev.mysql.com/doc/refman/5.5/en/fractional-seconds.html
http://www.jb51.net/article/51521.htm
3、PostgreSQL的timestamp,和MySQL類似,但是秒以下級別的精度有6位(也就是微秒,感覺各種神翻譯把microsecond翻譯成了毫秒),但是誰又能保證這個級別的時間戳就不會重復呢?
可以參考:
http://www.postgresql.org/docs/current/static/datatype-datetime.html
http://www.yiibai.com/manual/postgresql/datatype-datetime.html
那么在以上三種數據庫中,我們選擇了序號器+觸發器(Cache需要設置大一點,保證性能)的方式來搞定這個事情,注意,這里觸發器需要處理update的情況。
剩下的事情大家應該都會了,就是比較一個范圍的問題了。