当我在最后一次选择中添加算术时,收到此查询的以下错误消息...这是一个非常简单的计算,因此不确定问题是什么:
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秒。
致命错误:允许的内存大小为33554432字节耗尽(尝试过 在第0行的Unknown中分配505364672个字节
$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);
更新:
计算未按预期运行:
TIMESTAMPDIFF(第二,UTC_TIMESTAMP(),FROM_UNIXTIME(UNIX_TIMESTAMP() + alerts.email_rate * 60))AS sending_in
使用它作为测试...差异应该是900秒,但它返回-13500。
TIMESTAMPDIFF(第二,UTC_TIMESTAMP(),FROM_UNIXTIME(UNIX_TIMESTAMP() + 15 * 60))AS sending_in
更新:
我的错误- 返回正确的值:
TIMESTAMPDIFF(第二,现在(),FROM_UNIXTIME(UNIX_TIMESTAMP()+ 15 * 60))AS sending_in
工作解决方案:
看起来有点草率,但这很有效。 TIMESTAMPDIFF使用当前时区...我的last_email
值是一个unix时间戳,这是FROM_UNIXTIME发挥作用的地方。因为last_email
是无符号整数,所以除非转换为有符号整数,否则算法将无法正常工作。我总是将我的时间戳设置为无符号的原因是因为永远不会有负面的,但是在使用MySQL进行算术的情况下这会导致问题。
TIMESTAMPDIFF(第二,现在(), FROM_UNIXTIME(CONVERT(alerts.last_email,SIGNED)+ alerts.email_rate * 60))AS sending_in
答案 0 :(得分:1)
这似乎是PHP错误,而不是MySQL错误。我怀疑调用fetchAll
函数时会发生此错误;它是导致错误的数组$results
的分配。 (我只是猜测。)根据错误消息,尝试分配差不多482 MB的内存,但PHP限制为32 MB。
(我认为PHP设置了这个限制,但我不认为你真的想去那里......因为似乎没有任何理由需要分配那么多记忆。
部分问题是fetchAll,同时将结果集中的每一行检索到内存中。
但是,如果只在SELECT列表中添加最后一个表达式时才会发生这种情况,我怀疑PDO是为最后一个表达式的结果保留了过度的内存量。就像,MySQL在元数据中报告一个奇怪的数据类型和/或PDO没有检测到该表达式返回的正确数据类型,并且正在使用一些巨大的分配来存储它。
为了调试这个,尝试更改该查询以返回一个文字整数值来代替最后一个表达式,即替换它:
alerts.last_email + (alerts.email_rate * 60) - UNIX_TIMESTAMP() AS sends_in
用这个:
42 AS sends_in
看看PHP是否会出现同样的错误消息。如果没有,我怀疑PDO没有将原始表达式视为一个简单的整数类型。下一步是将该表达式的结果CAST或CONVERT转换为整数数据类型... 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日期时间函数。
我不确定我是否回答了你的问题。我甚至不确定你问了一个问题。