2014-09-22 60 views
0

收到此查詢以下錯誤消息,當我在最後選擇添加算術......這是一個非常簡單的計算所以不知道是什麼問題:算術mysql的select語句 - 內存大小錯誤

alert.last_email is a utc timestamp (unsigned integer) 
alerts.email_rate is value in minutes (unsigned integer) 

這是一個消息隊列...我試圖讓sends_in成爲一個秒數的消息將發送。

例如使用正常時間而不是時間戳...在晚上7點發送的最後一封電子郵件,費率爲15分鐘,所以它將在7:15發送。如果當前時間是7:10,那麼發送時間是5分鐘或者300秒。

Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 505364672 bytes) in Unknown on line 0

$stmt = $db->prepare(" 
    SELECT 
     users.username AS username, 
     computers.computer_name AS computer_name, 
     alerts.last_email AS last_email, 
     alerts_queue.alert_id AS alert_id, 
     alerts_queue.event_title AS event_title, 
     alerts_queue.event_target AS event_target, 
     alerts_queue.capture_timestamp AS capture_timestamp, 
     alerts.last_email + (alerts.email_rate * 60) - UNIX_TIMESTAMP() AS sends_in 
    FROM computers 
    INNER JOIN users 
     ON users.computer_id = computers.computer_id 
    INNER JOIN alerts 
     ON alerts.user_id = users.user_id 
    INNER JOIN alerts_queue 
     ON alerts_queue.user_id = alerts.user_id 
    WHERE computers.account_id = :cw_account_id AND computers.status = :cw_status 
"); 

$binding = array(
    'cw_account_id' => $_SESSION['user']['account_id'], 
    'cw_status' => 1 
); 
$stmt->execute($binding); 

$results = $stmt->fetchAll(PDO::FETCH_ASSOC); 

UPDATE:

計算不按預期工作:

TIMESTAMPDIFF(SECOND, UTC_TIMESTAMP(), FROM_UNIXTIME(UNIX_TIMESTAMP() + alerts.email_rate * 60)) AS sends_in

使用這個作爲測試...的差額爲900秒,但它返回-13500。

TIMESTAMPDIFF(SECOND, UTC_TIMESTAMP(), FROM_UNIXTIME(UNIX_TIMESTAMP() + 15 * 60)) AS sends_in

UPDATE:我的一部分

錯誤 - 這將返回正確的值:

TIMESTAMPDIFF(SECOND, NOW(), FROM_UNIXTIME(UNIX_TIMESTAMP() + 15 * 60)) AS sends_in

工作液:

它看起來有點邋遢,但是這作品。 TIMESTAMPDIFF使用當前時區...我的last_email值是一個unix時間戳,這是FROM_UNIXTIME進場的地方。因爲last_email是一個無符號整數,除非將其轉換爲有符號整數,否則算術將無法正常工作。我總是把我的時間戳設置爲無符號的原因是因爲永遠不會有負面的,但是在使用MySQL進行算術的情況下,這會造成問題。

TIMESTAMPDIFF(SECOND, NOW(), FROM_UNIXTIME(CONVERT(alerts.last_email,SIGNED) + alerts.email_rate * 60)) AS sends_in

+0

這不是一個mysql錯誤。您可能會返回過多的數據行,導致內存過載。 – Robbert 2014-09-22 21:16:28

+0

在這個測試中,只有兩行數據......沒有最後一次選擇與數學有關的情況下工作得很好。 – user756659 2014-09-22 21:17:18

+2

您是否嘗試過使用MySQL的內置函數? 'TIMESTAMPDIFF(SECOND,FROM_UNIXTIME(alerts.last_email + alerts.email_rate * 60),NOW())AS sending_in'或類似的東西?理想情況下,時間將存儲爲一個DATETIME而不是一個INT ... – miken32 2014-09-22 21:32:15

回答

1

這似乎是一個PHP錯誤,而不是MySQL錯誤。我懷疑當調用fetchAll函數時會發生此錯誤;並且它是導致錯誤的數組$results的分配。 (我只是猜測。)根據錯誤消息,有嘗試分配幾乎482 MB的內存,但PHP的限制是32 MB。我想在PHP中有一個設置來設置這個限制,但我不認爲你真的想去那裏...因爲似乎沒有任何理由需要分配那麼多的內存。問題的

部分是使用fetchall,檢索ResultSet中的每一行到內存在同一時間。

但是,如果當你添加在SELECT列表中最後一個表達式這只是發生,我懷疑的是, PDO保留過於簡單的這個最後一個表達式的結果的內存量。例如,MySQL在元數據中報告了一個奇怪的數據類型,並且/或者PDO沒有檢測到正確的表達式返回的數據類型,並使用一些巨大的分配來存儲它。與此

alerts.last_email + (alerts.email_rate * 60) - UNIX_TIMESTAMP() AS sends_in 


進行調試本,請嘗試更改該查詢的地方,最後一個表達式返回面值整數值,即,更換此

42 AS sends_in 

然後看看PHP是否會用相同的錯誤消息來咆哮。如果沒有,我懷疑PDO沒有看到你的原始表達式是一個簡單的整數類型。下一步將是投或轉換表達式的結果爲整數數據類型... CONVERT(expr,UNSIGNED)CONVERT(expr,SIGNED)

也就是說,替換最後一個表達式:

CONVERT(alerts.last_email + (alerts.email_rate * 60) - UNIX_TIMESTAMP(),SIGNED) 
    AS sends_in 

並給予一掄,和看看有多大的煙球。

就實際的MySQL語句而言,我認爲可能會出現一個嘗試減去無符號整數的錯誤。 (我認爲SQL_MODE中有一些東西可以控制這種行爲,我認爲行爲取決於MySQL版本)。將無符號整數轉換/轉換爲帶符號(64位)整數可能是必要的,這可能很醜陋工作:

CONVERT(CONVERT(alerts.last_email,SIGNED) + (CONVERT(alerts.email_rate,SIGNED) * 60) 
    - CONVERT(UNIX_TIMESTAMP(),SIGNED),SIGNED) 
    AS sends_in 

就個人而言,我寧願避免無符號整數數學與日期時間和時間戳值,並利用MySQL日期時間函數。


我不確定我是否回答了您的問題。我甚至不知道你問了一個問題。

+0

明確設置爲42可以正常工作。使用第一個CONVERT表達式給出了完全相同的錯誤。使用第二個表達式工作。我認爲你把它釘在頭上 - 這是無符號整數的使用......我總是這樣做的習慣,但在這種情況下,它造成了這個問題。 – user756659 2014-09-22 22:12:43

+0

使用解決方案的組合添加了上述工作解決方案。使用日期時間函數並需要轉換我自己的時間戳值。謝謝! – user756659 2014-09-22 22:42:50