sql - LINQ 订单依据。它总是返回相同的有序列表吗?

标签 sql .net sql-server linq linq-to-objects

我正在尝试一个简单的 OrderBy 语句。

要订购的目标数据如下所示:

[
  {"id":40, "description":"aaa", "rate":1},
  {"id":1,  "description":"bbb", "rate":1},
  {"id":4,  "description":"ccc", "rate":2},
  {"id":19, "description":"aaa", "rate":1} 
]

然后我按费率属性订购商品。

奇怪的是,如果我“排序”它们,它会按给定的偏移量“跳过”一些项目,然后仅“获取”部分数据。

例如,

var result = items.OrderBy(i => i.rate);
var result = result.Skip(2);
var result = result.Take(2);

结果大部分看起来都不错,但“边缘情况”项根本不返回。

例如

如果第一个结果返回为

    [{"id":40, "description":"aaa", "rate":1}, {"id":1, "description":"bbb", "rate":1}]

第二个结果返回如下

    [{"id":1, "description":"bbb", "rate":1}, {"id":4, "description":"ccc", "rate":2}]

第二次查询调用尚未返回项目“id: 19”。相反,项目“id: 1”已返回两次。

我的猜测是,每次 OrderBy 按给定属性进行排序时,SQL OrderBy 语句不会生成相同的有序列表,但共享相同属性的组内的确切顺序可能会发生变化。

幕后的确切机制是什么?

最佳答案

简短回答: LINQ to Objects 使用稳定的排序算法,因此我们可以说它是确定性的,而 LINQ to SQL 依赖于通常是不确定性的 Order By 的数据库实现。

确定性排序算法是一种在不同的运行中始终具有相同行为的算法。

在您的示例中,您的 OrderBy 子句中有重复项。对于保证排序和预测排序,顺序子句之一或顺序子句的组合必须是唯一的。

在 LINQ 中,您可以通过添加另一个 OrderBy 子句来引用您的唯一属性来实现它,例如
items.OrderBy(i => i.Rate).ThenBy(i => i.ID) .

长答案:

LINQ to Objects 使用稳定排序,如以下链接中所述:MSDN .

在 LINQ to SQL 中,它取决于底层数据库的排序算法,并且通常是不稳定的排序,例如在 MS SQL Server ( MSDN ) 中。

在稳定排序中,如果两个元素的键相等,则保留元素的顺序。相反,不稳定排序不会保留具有相同键的元素的顺序。

Wikipedia example

因此,对于 LINQ to SQL,排序通常是不确定的,因为RDMS(关系数据库管理系统,如 MS SQL Server)可能直接使用不稳定的排序算法和随机主元选择或随机性可能与数据库首先访问文件系统中的哪一行有关。

例如,假设文件系统中的一个页面的大小最多可以容纳 4 行。

如果插入以下数据,页面将被填满:

     Page 1
| Name | Value |
|------|-------|
|   A  |   1   |
|   B  |   2   |
|   C  |   3   |
|   D  |   4   |


如果需要插入新行,RDMS 有两个选项:

  1. 创建一个新页面来分配新行。
  2. 将当前页面分成两页。因此,第一页将包含名称 AB,第二页将包含 CD

假设 RDMS 选择选项 1(以减少索引碎片)。如果您插入名称为 C 和值 9 的新行,您将得到:

     Page 1              Page 2
| Name | Value |    | Name | Value |
|------|-------|    |------|-------|
|   A  |   1   |    |   C  |   9   |
|   B  |   2   |    |      |       |
|   C  |   3   |    |      |       |
|   D  |   4   |    |      |       |


可能名称列中的 OrderBy 子句将返回以下内容:

| Name | Value |
|------|-------|
|   A  |   1   |
|   B  |   2   |
|   C  |   3   |
|   C  |   9   | -- Value 9 appears after because it was at another page
|   D  |   4   |


现在,假设RDMS选择选项2(以提高具有多个轴的存储系统中的插入性能)。如果您插入名称为 C 和值 9 的新行,您将得到:

     Page 1              Page 2
| Name | Value |    | Name | Value |
|------|-------|    |------|-------|
|   A  |   1   |    |   C  |   3   |
|   B  |   2   |    |   D  |   4   |
|   C  |   9   |    |      |       |
|      |       |    |      |       |


可能名称列中的 OrderBy 子句将返回以下内容:

| Name | Value |
|------|-------|
|   A  |   1   |
|   B  |   2   |
|   C  |   9   |  -- Value 9 appears before because it was at the first page
|   C  |   3   | 
|   D  |   4   |


关于您的示例:

我相信您在问题中输入了一些错误,因为您使用了 items.OrderBy(i => i.rate).Skip(2).Take(2);第一个结果不显示 Rate = 2 的行。这是不可能的,因为 Skip将忽略前两行,它们有 Rate = 1 ,因此您的输出必须显示包含 Rate = 2 的行.

您已将您的问题标记为 database ,所以我相信您正在使用 LINQ to SQL。在这种情况下,结果可能是不确定的,您可能会得到以下结果:

结果 1:

[{"id":40, "description":"aaa", "rate":1},
 {"id":4, "description":"ccc", "rate":2}]

结果2:

[{"id":1, "description":"bbb", "rate":1},
 {"id":4, "description":"ccc", "rate":2}]

如果您使用过items.OrderBy(i => i.rate).ThenBy(i => i.ID).Skip(2).Take(2);那么唯一可能的结果是:

[{"id":40, "description":"aaa", "rate":1},
 {"id":4, "description":"ccc", "rate":2}]

关于sql - LINQ 订单依据。它总是返回相同的有序列表吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25922348/

相关文章:

mysql - 蛋糕PHP : populating 2 fields with the same foreign key and write to database

c# 在数据库中存储用户设置

sql-server - 透视查询以返回多个重复组?

sql - 案例当...然后

sql - 如何选择一年中的每个星期一日期和每个星期五日期

MySQL Integer比较速度(= vs <>)

.net - 获取计算机的上次唤醒时间

.net - DLL 可以调用 .NET DLL 吗?

sql-server - SQL Server 存储过程 : Read data from URL text file

sql-server - 仅更新 DateTime 的日期部分