如何避免 '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
将会改变排序。
如何防止这种情况发生?
让我们假设给定示例如下:
- 我做不到一个
select
。
- 我不知道在执行外部
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 之类的东西)你只是在描述你想要的结果集。服务器生成符合您的规范的结果。
我有一个案例,我从另一个 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
应用了什么顺序。所以,如果我从加入的 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 之类的东西)你只是在描述你想要的结果集。服务器生成符合您的规范的结果。