An ObjectId is a 12-byte unique identifier consisting of:
- a 4-byte value representing the seconds since the Unix epoch,
- a 3-byte machine identifier,
- a 2-byte process id, and
- a 3-byte counter, starting with a random value.
由于前 4 個 byte 表示時間,是以 ObjectId 可以反映時間。預設情況下,前 4 個 byte 表示的時間為檔案建立時伺服器的時間。
如果你使用 ObjectId 代替時間,那麼導入過去存在的資料時 ObjectId 可能發生沖突[1]。
針對同一時刻建立 ObjectId
根據過去的某一時刻建立 ObjectId 會重複,因為前 3 種 byte 都一樣,隻有最後 3 個 byte 不一樣。
對于 PyMongo Driver:
from bson import ObjectId
# timestamp
str(ObjectId())[:8]
'5b2b0778'
str(ObjectId())[:8]
'5b2b0779'
# machine id 和 process id
str(ObjectId())[8:18]
'0e118bd5c7'
str(ObjectId())[8:18]
'0e118bd5c7'
# counter
str(ObjectId())[18:]
'a5b135'
str(ObjectId())[18:]
'a5b136'
假如針對 timestamp
5b2b0778
生成訂單,由于是同一機器、程序,是以前 3 種 byte 都相同。而最後的 counter 是在程序啟動時初始化一個随機值,然後進行遞增。任意兩個 ObjectId 相同的機率為 1677 萬分之一:
# 3 byte 為 24 位
2 ** 24 / 10000
1677
但随着訂單的增多,沖突的機率會越來越大。
是以不能采用針對某一時刻建立 ObjectId 的方法。
分散建立
設定一個時間區間,然後将檔案分散到每一秒建立。如果時間區間足夠大,那麼效果就和正常建立 ObjectId 一樣。時間區間可以根據理想沖突率和檔案數倒推出來。
參考
- https://dzone.com/articles/using-and-abusing-mongodb