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

How to avoid a 'where' clause affecting row ordering?

我有一个案例,我从另一个 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 应用了什么顺序。所以,如果我从加入的 table 订购,我不知道我需要在这里加入它。

关于我的用例的更多信息

有一个提供内部 select 的查询构建器,如果我想申请,它可能会应用连接到该内部 select 的第三个 table 的订单同样的顺序,我需要知道加入了什么 table,而对于这个糟糕的查询构建器,我不知道

我建议您不要依赖我的 SQL 产生的隐式排序(因为根据 Bohemian 的评论,没有隐式排序)。相反,您应该使用 ORDER BY 语句和 select 查询中的列之一,您应该根据这些列对结果进行排序。这样您就可以确保无论 WHERE 子句如何,结果始终以相同的方式呈现。

tl;dr 如果您希望结果集中的特定顺序,请使用 ORDER BY.

在没有 ORDER BY 子句的情况下,来自任何 RDMS 服务器的结果集中行的排序形式上是 unpredictable。 Unpredictable就像随机的,除了更糟。随机排序意味着您每次 运行 查询时都会以不同的顺序获取行。真正的随机排序(如果存在)会使简单的单元测试在您关于排序的假设失败时难以通过。

Unpredictable 意味着 你会以相同的顺序得到它们,直到你不这样做。 这意味着你的单元测试将通过,你的系统测试将通过,并且您的系统将在生产六个月后失败,如果它取决于结果集排序。

为什么会这样?服务器的查询规划器可以随意使用任何算法来满足您提供的查询。对于不同类型的 table 和不同大小的 table,这些算法的工作方式不同。如果您不通过指定结果集排序来约束查询规划器,它可能会选择一些算法,这些算法给出的排序对程序员来说似乎很奇怪。

从字面上看,查询规划器内置了程序员数千年的优化价值。

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