2014-05-01 44 views
0

這可能過於本地化,但希望可能有一些信息在那裏,我根本無法找到。DATE_SUB和INTERVAL計算可能是錯誤的

背景:我們有一個帶有兩個獨立Java守護進程的系統;一個創建數據並插入到數據庫中,另一個獲取最新的數據集(不超過1個小時),並推送到客戶端。

問題:從此表中抓取的數據偶爾會大於1小時。時差可以在2小時到幾個月之間。

當前查詢:獲取1小時數據是一個兩步過程。首先,我們的「後備」通過設置一個隨機負數一組記錄:

UPDATE tracking_records as target 
    JOIN 
    (SELECT tracking_records.id, `set`, unit_id, tracking_records.record_time 
    FROM tracking_records 
    WHERE `set` IS NULL and record_time > DATE_SUB(NOW(), INTERVAL 1 HOUR) 
    ORDER BY record_time DESC LIMIT 48) source 
    ON source.id = target.id 
SET target.`set` = -1371504452; 

注:-1371504452是一個示例值;它是在Java中隨機生成的。每個查詢的LIMIT 48保持不變。

然後我們只需選擇包含那個隨機set值的列。

這是tracking_records表的結構:

+-------------+---------------------+ 
| Field  | Type    | 
+-------------+---------------------+ 
| id   | bigint(20) unsigned | 
| unit_id  | int(11)    | 
| record_time | datetime   | 
| latitude | int(11)    | 
| longitude | int(11)    | 
| created_at | datetime   | 
| updated_at | datetime   | 
| set   | int(11)    | 
+-------------+---------------------+ 

正如你所看到的,查詢應該只匹配記錄中,其中set欄爲空並且其中記錄時間是在1小時前。

如前所述,我檢測到幾個小時的時間差異,最長爲幾個月(迄今爲止檢測到的最老的是2013-09-23 11:01:08)。考慮到WHERE子句的時間限制,這對我來說沒有意義。

我們使用的MySQL版本5.5.29-0ubuntu0.12.04.2

問:我很困惑,我想知道,如果有一個錯誤,或者其他問題而會導致時間計算失敗如此劇烈和隨機。要麼是這樣,要麼是查詢本身存在問題,我根本沒有看到。

有沒有人在這個版本的MySQL中觀察到錯誤的時間比較,DATE_SUB()函數或INTERVAL計算的問題,這可能解釋我看到的異常時間?

+0

99%的時間,當你使用一個行之有效的工具時,問題不在於工具,而在於用戶。你確定'record_time'是'DATETIME'的值,而不僅僅是時間(以小時爲單位,而不是幾小時,幾天,幾個月,幾年......)?它是否可以在任何時候更新? – Floris

+0

@Floris是的,'record_time'總是一個'datetime',包含正確的日期和時間值,並按照這樣輸入。我再次檢查以確認。檢測這樣的問題很容易。不,在這種情況下,輸入「record_time」的值永遠不會改變。守護進程中沒有其他更新語句。唯一被操縱的列是'set'列。 –

+1

我希望確保在進行選擇之前沒有隨機值的條目已經存在。爲什麼不總是使用相同的值?首先,將所有'1'值設置爲'0';然後將你需要的記錄設置爲'1'。 – Floris

回答

1

我們假設id是表的PRIMARY KEY,或者它是唯一鍵。

最可能的懷疑是「隨機」數字不是唯一的。很可能,Java使用僞隨機數生成器,它實際上會從同一個種子生成一個可重複的數字序列。

我推薦一個號碼發生器產生獨特值,而不是隨機值,因爲同樣的隨機值綁定在某個時候出現。

如果發生這種情況,48行的集合將被更新爲「隨機」值,但隨後的基於該「隨機」值檢索這些行的查詢也將拾取以前更新的行到相同的「隨機」值。


雖這麼說,你表現出的SQL語句,有可能是一個「碰撞」的小窗口,如果兩個這些語句的運行在精確的同一時間。 (這個內聯視圖被物化成一個臨時的MyISAM表,然後外部查詢運行,我不確定內聯視圖查詢是否在跟蹤記錄的行上獲得排它或意向排他鎖,但是碰撞的症狀在那裏將是一個後續查詢沒有找到48行與指定set價值,因爲另一個查詢過寫有它自己的價值的價值。


這不太可能你已經發現在MySQL DATETIME處理的錯誤。這代碼已經被使用了很多年,並且不太可能在這裏引入了一個bug(我已經使用了它超過十年(版本3.23,4.x,5.1,5.5),並且我從來沒有遇到過DATETIME的錯誤(我被粗暴地引入了記錄的行爲,但從未遇到過真正的bug。)

請注意,DATE_SUB函數是沒有必要的;你可以得到同樣的結果:

NOW() - INTERVAL 1 HOUR 

注意NOW()得到的語句或塊的開始計算;我們寧願將其用於其他功能,主要是因爲它的複製安全。原始執行時評估的值保存在二進制日誌中,以便可以在副本數據庫上應用相同的值。每次調用函數時,返回當前時間的其他函數都會得到重新評估,並且該值不會保留用於複製。

+0

是的,'id'確實是主要和唯一的。抱歉應該提到這一點。這絕對解決了這個問題 - 你是絕對正確的,這是「隨機」數字是罪魁禍首。最初,在推進之後,set值被更新爲正值,因此用僞隨機負數選擇從來都不是問題。但是我們在運行多個守護進程時試圖解決一些死鎖問題的同時移除了這個功能。鑑於數據的巨大增長率,應該意識到這一切。感謝您的幫助! –