对于MySQL数据库(InnoDB)的SELECT
查询,我们遇到了一个奇怪的问题。
以下查询错误地返回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
而以下查询正确返回没有匹配的记录:
select `ID`
from `AccessTables`
where `numTableID` = 14
AND `numUserCatID` IN (7,253)
AND (`numUpdateCat` = 2 OR `numUpdateItems` = 2)
limit 1
如您所见,这些查询之间的唯一区别是“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);
(编辑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;
输出:
"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"
QUERY2:
EXPLAIN EXTENDED SELECT `ID`
FROM `AccessTables`
WHERE `numTableID` = 14
AND `numUserCatID` IN (7,253)
AND (`numUpdateCat` = 2 OR `numUpdateItems` = 2)
LIMIT 1;
输出:
"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"
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;
输出:
"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"
编辑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;
输出:
"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"
因此,返回正确结果的查询(找到0条记录)似乎与numUserCatID上的索引一起使用,而返回错误结果的查询(找到1条记录)似乎与numTableID上的索引一起使用。
奇怪...!
编辑nr。 5:
通过其他专栏订购,例如。 dateInsert(表示记录插入表中的日期/时间戳)也会更改查询结果。
然后再次没有返回记录,并且使用的索引再次是numUserCatID上的索引。
我们使用'按ID
asc排序',因为我们假设ID始终代表记录插入数据库的顺序。
但是dateInsert在我们的例子中基本相同。
使用常规键列进行排序而不是主键时,大型数据库是否会出现性能损失?
答案 0 :(得分:2)
如果这确实发生了,那就是一个错误。“真的”我的意思是这些是您发送到数据库服务器的确切查询,并且基础表尚未更新时间。
类似(但不完全相同)的问题在于: MDEV-2662
请将问题报告给MariaDB团队。
要解决当前问题,请尝试重新编写查询,例如不使用IN
替换;
AND numUserCatID IN (7,253)
使用:
AND (numUserCatID = 7 OR numUserCatID = 253)
并检查您是否得到相同的错误结果。
答案 1 :(得分:0)
我与MarjaR合作,经过测试:MariaDB 5.5中的这个错误在5.5.37中得到解决