Maria DB 中发生奇怪的缓存,查询选择最小的可用 id

Posted

技术标签:

【中文标题】Maria DB 中发生奇怪的缓存,查询选择最小的可用 id【英文标题】:Weird caching happening in Maria DB with query selecting minimal available id 【发布时间】:2021-08-08 22:07:09 【问题描述】:

我有一个查询,它选择表中可用的最低可用 id。它在我的测试中运行完美,但我意识到,它在生产中总是返回 9。所以我删除了 ID 号 6(较低)来检查会发生什么。 (实际上我希望,我可能会以这种方式向 phpmyadmin 展示,缓存不是一个聪明的主意)事实上,它给了我免费的 id 6。所以我很高兴地再次占据了它,并试图获得下一个最大的 Id,即:6。正如你可能猜到的,我一点也不开心。 我的sql查询如下:

set @i=0;
select max(if(@i=SMS_Id,@i:=SMS_Id+1,@i)) AS Min_ID from sms_obtenir order by SMS_Id

以及它返回的内容:

嗯,你可以清楚地看到,返回是“6”。

但我的数据看起来像这样(出于隐私原因,电话号码被审查):

如您所见,正确答案是 10。所以我想,“如果我从查询中删除 max 会发生什么?”所以我做到了:

set @i=0;
select if(@i=SMS_Id,@i:=SMS_Id+1,@i) AS Min_ID from sms_obtenir order by SMS_Id

结果:

所以,事实上,整个 if-case 都是正确的,最后返回的数字是 10。 所以你会期望,只要你在它周围加上一个 max(...),回报就是 10。但事实并非如此。是 6。 任何人都有一个想法,数据库到底是如何产生这个结果的? (不应该是 phpmyadmin 的问题,也发生在 PHP 代码中。)

编辑: 我已经尝试了 Barmar 建议的查询,但并没有解决问题。但是,它有一个有趣的副作用,可能导致结果为 6。因此,查询如下:

set @i=0;
select max(if(@i=SMS_Id,@i:=SMS_Id+1,@i)) AS Min_ID 
from (
    SELECT SMS_Id
    FROM sms_obtenir 
    order by SMS_Id
) AS SMS_Id

查询最里面的结果

SELECT SMS_Id
FROM sms_obtenir
ORDER BY SMS_Id 

如您所料,返回 0,1,2,3,4,5,6,7,8,9,11,....

但是,一旦我删除查询的最大值,它就不会返回(应该)1、2、3、4、5、6、7、8、9、10、10、10、10, ... 但以下查询

set @i=0;
select if(@i=SMS_Id,@i:=SMS_Id+1,@i) AS Min_ID 
from (
    SELECT SMS_Id
    FROM sms_obtenir 
    order by SMS_Id
) AS SMS_Id LIMIT 0,75

返回 36 次 0,然后返回 1,2,3,4,5,6,6,6,6,6,....

所以 max-function 似乎返回了正确的值,但是我可能对过程没有太多了解,但我很确定,上述过程的结果不是,应该根据内部函数的结果。 所以,我决定也选择 SMS_Id,这样我就可以看到内部语句发生了什么,我不得不说,我很慌张,Maria DB 从 ordering 中得到了多么惊人的定义:

结果如下:

【问题讨论】:

【参考方案1】:

您不应在具有ORDER BY 的同一查询中设置变量,因为可以在分配SELECT 列表中的变量 之后进行排序。您需要在子查询中进行排序。

select max(if(@i=SMS_Id,@i:=SMS_Id+1,@i)) AS Min_ID 
from (
    SELECT SMS_id
    FROM sms_obtenir 
    order by SMS_Id
) AS x

【讨论】:

嘿。感谢您的回答。 :) 但它仍然返回 6 而不是 10。似乎不是问题。当我删除函数周围的 max() 时,现在它为所有值返回 0。【参考方案2】:

好的,Barmars 的回答让我找到了解决问题的正确方法。 (不知道,设置变量后可能会发生排序) 但是,解决方案的问题是,我不能保证,它有效。到目前为止,它在我的情况下有效,因为 MariaDB 似乎以一种非常特殊的方式执行该语句(编写了一个测试,以无序组合添加 id,因此 id 在开始时不会在 DB 中自动排序),但是正如 Barmar 指出的那样,通常正确的方法应该是首先在子查询中对 SMS_Ids 进行排序,然后设置变量。 但是,这在我的 Maria DB 版本中不起作用: 它在子查询中对 SMS_Ids 进行排序,然后放弃排序并将变量设置在无序列表上。当您直接从变量中选择 max 时,它也会放弃订单。因此,为了“确保”它是有序的(更确切地说,希望它永远不会做不同的事情),正确的解决方案是创建一个子查询,首先为变量设置所有 Min_Ids,然后选择该子查询的最大值。查询是:

set @i=0;
select max(Min_Id) FROM (
select if(@i=SMS_Id,@i:=SMS_Id+1,@i) 
AS Min_ID from sms_obtenir 
order by SMS_Id
) 
AS Min_Id

【讨论】:

以上是关于Maria DB 中发生奇怪的缓存,查询选择最小的可用 id的主要内容,如果未能解决你的问题,请参考以下文章

Maria DB 安装

如何重命名 maria DB 中的列名

需要帮助以在 DB2 中进行正确的选择查询

Maria DB:MySQL 服务器已消失,错误日志中没有任何内容

Maria DB下载安装教程

Maria-DB