我们遇到了一个SELECT针对MySQL数据库(InnoDB)的查询的奇怪问题.
以下查询错误地返回1个匹配的记录:
select `ID`
from `AccessTables`
where `numTableID` = 14
AND `numUserCatID` IN (7,253)
AND (`numUpdateCat` = 2 OR `numUpdateItems` = 2)
order by `ID` asc
limit 1
Run Code Online (Sandbox Code Playgroud)
而以下查询正确返回没有匹配的记录:
select `ID`
from `AccessTables`
where `numTableID` = 14
AND `numUserCatID` IN (7,253)
AND (`numUpdateCat` = 2 OR `numUpdateItems` = 2)
limit 1
Run Code Online (Sandbox Code Playgroud)
如您所见,这些查询之间的唯一区别是"order by"子句.
ID查询中请求的列是表的自动生成的主键列.
第一个查询中返回的记录是一个记录,如果'或'子句周围没有括号,则会找到该记录.但是在查询的那一部分周围有括号,所以我不明白为什么在这里返回此记录.然后,只有在查询中存在"order by"子句时.
正在使用的MySQL版本是:MySQL服务器:5.5.32-MariaDB-log
这里的任何人都可以对这个问题有所了解吗?提前致谢.
(编辑:省略括号确实会返回一行,但这是第一行查询返回的行)
insert into `AccessTables`(`ID`,`numUserCatID`,`numTableID`,`numUpdateCat`,`numPublishCat`,`numUpdateItems`,`dateInsert`,`dateUpdate`,`numInsertAuthorID`,`numUpdateAuthorID`,`numViewItems`) values (71,15,14,0,0,2,'2008-03-13 23:38:47','2013-04-04 09:34:36',0,513,2);
Run Code Online (Sandbox Code Playgroud)
(编辑nr.2:没有MariaDB,但.... http://sqlfiddle.com/#!2/2a922/8)
编辑nr.3,针对真正的MariaDB运行这些查询:
查询1:
EXPLAIN EXTENDED SELECT `ID`
FROM `AccessTables`
WHERE `numTableID` = 14
AND `numUserCatID` IN (7,253)
AND (`numUpdateCat` = 2 OR `numUpdateItems` = 2)
ORDER BY `ID` ASC
LIMIT 1;
Run Code Online (Sandbox Code Playgroud)
输出:
"id" "select_type" "table" "type" "possible_keys" "key" "key_len" "ref" "rows" "filtered" "Extra"<br />
"1" "SIMPLE" "AccessTables" "range" "numUserCatID,numTableID,numUpdateCat,numUpdateItems" "numTableID" "8" \N "136" "11.03" "Using where"
Run Code Online (Sandbox Code Playgroud)
QUERY2:
EXPLAIN EXTENDED SELECT `ID`
FROM `AccessTables`
WHERE `numTableID` = 14
AND `numUserCatID` IN (7,253)
AND (`numUpdateCat` = 2 OR `numUpdateItems` = 2)
LIMIT 1;
Run Code Online (Sandbox Code Playgroud)
输出:
"id" "select_type" "table" "type" "possible_keys" "key" "key_len" "ref" "rows" "filtered" "Extra"<br />
"1" "SIMPLE" "AccessTables" "range" "numUserCatID,numTableID,numUpdateCat,numUpdateItems" "numUserCatID" "8" \N "20" "75.00" "Using index condition; Using where"
Run Code Online (Sandbox Code Playgroud)
QUERY3:
EXPLAIN EXTENDED SELECT `ID`
FROM `AccessTables`
WHERE `numTableID` = 14
AND (numUserCatID = 7 OR numUserCatID = 253)
AND (`numUpdateCat` = 2 OR `numUpdateItems` = 2)
ORDER BY `ID` ASC
LIMIT 1;
Run Code Online (Sandbox Code Playgroud)
输出:
"id" "select_type" "table" "type" "possible_keys" "key" "key_len" "ref" "rows" "filtered" "Extra"<br />
"1" "SIMPLE" "AccessTables" "range" "numUserCatID,numTableID,numUpdateCat,numUpdateItems" "numTableID" "8" \N "136" "11.03" "Using where"
Run Code Online (Sandbox Code Playgroud)
编辑nr.4:删除'limit 1'与删除'order by'的结果相同:没有找到任何行.
查询4:
EXPLAIN EXTENDED SELECT `ID`
FROM `AccessTables`
WHERE `numTableID` = 14
AND `numUserCatID` IN (7,253)
AND (`numUpdateCat` = 2 OR `numUpdateItems` = 2)
ORDER BY `ID` ASC;
Run Code Online (Sandbox Code Playgroud)
输出:
"id" "select_type" "table" "type" "possible_keys" "key" "key_len" "ref" "rows" "filtered" "Extra"<br />
"1" "SIMPLE" "AccessTables" "range" "numUserCatID,numTableID,numUpdateCat,numUpdateItems" "numUserCatID" "8" \N "20" "75.00" "Using index condition; Using where; Using filesort"
Run Code Online (Sandbox Code Playgroud)
因此,返回正确结果的查询(找到0条记录)似乎与numUserCatID上的索引一起使用,而返回错误结果的查询(找到1条记录)似乎与numTableID上的索引一起使用.
奇怪...!
编辑nr.5:
按另一列排序,例如.dateInsert(表示记录插入表中的时刻的日期/时间戳)也会更改查询结果.
然后再次没有返回记录,并且使用的索引再次是numUserCatID上的索引.
我们使用' IDasc '命令,因为我们假设ID总是代表记录插入数据库的顺序.
但是dateInsert在我们的例子中基本相同.
使用常规键列进行排序而不是主键时,是否会在大型数据库中出现性能损失?
如果真的发生这种情况,那就是一个错误。对于“真的”,我的意思是这些是您发送到数据库服务器的确切查询,并且基础表尚未同时更新。
类似(但不相同)的问题在这里:MDEV-2662
请将问题报告给 MariaDB 团队。
要解决眼前的问题,请尝试重写查询,例如不使用IN, 替换;
AND numUserCatID IN (7,253)
Run Code Online (Sandbox Code Playgroud)
和:
AND (numUserCatID = 7 OR numUserCatID = 253)
Run Code Online (Sandbox Code Playgroud)
并检查是否得到相同的错误结果。