我需要使用 LINQ 从 DB2 数据库查询记录。我有从数据库架构生成的实体,并尝试使用 Skip 和 Take 执行 LINQ 查询。基础表大约有 25 列,可能有 100 万条记录。当我在没有“Skip()”的情况下执行查询时,大约需要 0.508 毫秒才能完成。当我包含 Skip() 时,需要将近 30 秒。差别很大。
谁能告诉我为什么会这样?
更新: 这是我正在使用的 LINQ 查询。
var x = 30;
var results = context.ASSET_T
.OrderBy(c => c.ASSET_ID)
.Skip(x)
.Take(x)
.ToList();
更新: 所以我只是尝试更新查询,以便只返回单个列 ASSET_ID。当我只返回这一列时,使用 Skip() 的查询只需要 0.256 毫秒。
var x = 30;
var results = context.ASSET_T
.OrderBy(c => c.ASSET_ID)
.Skip(x)
.Take(x)
.Select(c => c.ASSET_ID)
.ToList();
如果我包含任何其他列,那么查询执行时间会增加戏剧性地。
例如下面的查询需要 10 秒才能执行。
var x = 30;
var results = context.ASSET_T
.OrderBy(c => c.ASSET_ID)
.Skip(x)
.Take(x)
.Select(c => new {
ASSET_ID = c.ASSET_ID,
ASSET_TYP = c.ASSET_TYP
ASSET_DESC = c.ASSET_DESC
})
.ToList();
更新:我现在发现我尝试查询的表中的列存在问题(可能与索引相关)。正如我上面提到的,当我执行仅返回 ASSET_ID 列的查询时,只需要 0.256 毫秒。如果我尝试执行 ONLY 返回 ASSET_DESC 的查询或 ONLY 返回 ASSET_TYP 的查询,则查询执行时间会跳至 9 秒左右。
这是否表明其他列当前尚未建立索引?
更新:我添加了上述 LINQ 查询的 SQL 输出。
SELECT
Project1.C1 AS C1,
Project1.ASSET_ID AS ASSET_ID,
Project1.ASSET_TYP AS ASSET_TYP,
Project1.ASSET_DESC AS ASSET_DESC
FROM ( SELECT Project1.ASSET_ID AS ASSET_ID, Project1.ASSET_TYP AS ASSET_TYP, Project1.ASSET_DESC AS ASSET_DESC, Project1.C1 AS C1, row_number() OVER (ORDER BY Project1.ASSET_ID ASC, Project1.ASSET_TYP ASC, Project1.ASSET_DESC ASC) AS row_number
FROM ( SELECT
Extent1.ASSET_ID AS ASSET_ID,
Extent1.ASSET_TYP AS ASSET_TYP,
Extent1.ASSET_DESC AS ASSET_DESC,
CAST(1 AS int) AS C1
FROM MYDB.ASSET_T AS Extent1
) AS Project1
) AS Project1
WHERE Project1.row_number > 1
ORDER BY Project1.ASSET_ID ASC, Project1.ASSET_TYP ASC, Project1.ASSET_DESC ASC FETCH FIRST 31 ROWS ONLY
您查看过为此查询生成的 SQL 吗?
据我所知,Skip() Take() 最终会生成一个使用名为 Row_Number() 的函数的生成语句。此函数以如下所示的方式在整个记录集中执行 - 在获取所需的开始值和结束值之间的值之前,将行号插入结果中作为第一个生成的列,这通常会使其在大型记录上变得非常非常慢套..
SELECT ...
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY [t0].[...]) AS [ROW_NUMBER], ... ,
FROM [table] AS [t0]
) AS [t1]
WHERE [t1].[ROW_NUMBER] BETWEEN @p0 + 1 AND @p0 + @p1
ORDER BY [t1].[ROW_NUMBER]
如果您可以使用索引数字列并对其进行排列,以便您读取 >= start_value AND <= end-value yourself, then move those values up by your paging amount it will use the index and return results in in milliseconds.
我拥有索引良好的数据库,其中包含数百条记录,而 Skip().Take() 最多可能需要 30 分钟才能获取 25 条记录。哪里直接读取大约需要20-40ms。
这意味着您必须考虑实现分页的编码方式,并且在您的情况下实现可能不切实际。
我猜这不是由于 linq,尝试先按索引列排序,然后跳过。 在第一种情况下,当您只获取时,它不会遍历其余记录,只选择顶部结果,而使用跳过则需要对它们进行排序以找出顺序,然后根据它进行跳过。