我有一个案例,我从另一个select
执行select
,如果我添加where
子句,则更改返回行的顺序。
示例:
SELECT t.id
FROM (
SELECT t.id
FROM table1 t
ORDER BY
t.viewsTotal ASC
LIMIT 20
OFFSET 0
) base
INNER JOIN table1 t ON base.id = t.id
LEFT JOIN table2 t2 ON t2.id = t1.secondTableId
# WHERE t2.someBoolColumn = FALSE
;
现在,内部select
和外部select
的顺序相同,但如果我取消注释where
条件,外部select
将更改排序
如何防止这种情况发生?
让我们假设以下示例:
select
。select
时,内部select
应用了哪个顺序。所以,如果我从一个联合表中订购,我不知道我需要在这里加入它。有一个提供内部选择的查询构建器,它可以通过连接到该内部选择的第三个表来应用顺序,如果我想应用相同的顺序,我需要知道哪些表被连接,以及在这个糟糕的查询构建器的情况下,我没有那个知识
答案 0 :(得分:4)
tl; dr如果您想在结果集中使用特定订单,请使用ORDER BY
。
任何没有ORDER BY
子句的RDMS服务器的结果集中行的排序正式不可预测。不可预测就像随机,除了更糟。随机排序意味着每次运行查询时,您都会以不同的顺序获取行。如果存在真正的随机排序,那么当你对排序的假设失败时,简单的单元测试很难通过。
不可预测意味着你将以相同的顺序获得它们,直到你没有。这意味着你的单元测试将通过,你的系统测试将通过,你的系统将失败六个月投入生产,如果它取决于结果集排序。
为什么会这样?服务器的查询计划程序可以自由使用任何算法来满足您提供的查询。对于不同类型的表和不同大小的表,这些算法的工作方式不同。如果您没有通过指定结果集排序来约束查询计划程序,那么它可能会选择一些算法来提供程序员看来很奇怪的排序。
从字面上看,查询规划人员已经在其中内置了数千个程序员年的优化。
对于习惯于各种编程语言所鼓励的程序性思维方式的人来说,有时很难将思维转换为SQL使用的声明/描述模式。使用SQL(至少没有像SELECT @a := @a+1
和其他hack这样的东西的干净SQL),你只需要描述你想要的结果集。服务器生成符合您的规范的结果。
答案 1 :(得分:1)
我建议你不要依赖于我的SQL产生的隐式排序(因为根据Bohemian的评论没有隐式排序)。相反,您应该使用ORDER BY语句并在查询中选择一个您应该按顺序排序结果的列。这样,无论WHERE子句如何,您都可以确保结果始终以相同的方式呈现。