如何避免影响行排序的'where'子句?

时间:2017-10-10 23:28:34

标签: mysql sql sql-order-by query-builder

我有一个案例,我从另一个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将更改排序

如何防止这种情况发生?

让我们假设以下示例:

  1. 我不能做一个select
  2. 我不知道在执行外部select时,内部select应用了哪个顺序。所以,如果我从一个联合表中订购,我不知道我需要在这里加入它。
  3. 有关我的用例的更多信息

    有一个提供内部选择的查询构建器,它可以通过连接到该内部选择的第三个表来应用顺序,如果我想应用相同的顺序,我需要知道哪些表被连接,以及在这个糟糕的查询构建器的情况下,我没有那个知识

2 个答案:

答案 0 :(得分:4)

tl; dr如果您想在结果集中使用特定订单,请使用ORDER BY

任何没有ORDER BY子句的RDMS服务器的结果集中行的排序正式不可预测。不可预测就像随机,除了更糟。随机排序意味着每次运行查询时,您都会以不同的顺序获取行。如果存在真正的随机排序,那么当你对排序的假设失败时,简单的单元测试很难通过。

不可预测意味着你将以相同的顺序获得它们,直到你没有。这意味着你的单元测试将通过,你的系统测试将通过,你的系统将失败六个月投入生产,如果它取决于结果集排序。

为什么会这样?服务器的查询计划程序可以自由使用任何算法来满足您提供的查询。对于不同类型的表和不同大小的表,这些算法的工作方式不同。如果您没有通过指定结果集排序来约束查询计划程序,那么它可能会选择一些算法来提供程序员看来很奇怪的排序。

从字面上看,查询规划人员已经在其中内置了数千个程序员年的优化。

对于习惯于各种编程语言所鼓励的程序性思维方式的人来说,有时很难将思维转换为SQL使用的声明/描述模式。使用SQL(至少没有像SELECT @a := @a+1和其他hack这样的东西的干净SQL),你只需要描述你想要的结果集。服务器生成符合您的规范的结果。

答案 1 :(得分:1)

我建议你不要依赖于我的SQL产生的隐式排序(因为根据Bohemian的评论没有隐式排序)。相反,您应该使用ORDER BY语句并在查询中选择一个您应该按顺序排序结果的列。这样,无论WHERE子句如何,您都可以确保结果始终以相同的方式呈现。