Linq to Entity Paging with large dataset太慢了
Posted
技术标签:
【中文标题】Linq to Entity Paging with large dataset太慢了【英文标题】:Linq to Entity Paging With Large dataset too slow 【发布时间】:2014-02-04 08:48:21 【问题描述】:我正在分析来自在线游戏的数百万场比赛的玩家数据。我正在尝试以块的形式将数据分页到内存中以减少加载时间,但是将 OrderBy
与 skip/take 一起使用需要的时间太长(即使是较小的查询也需要 20 多分钟)。
这是我的查询:
var playerMatches = (from p in context.PlayerMatchEntities
join m in context.MatchEntities
on p.MatchId equals m.MatchId
where m.GameMode == (byte) gameMode
&& m.LobbyType == (byte) lobbyType
select p)
.OrderBy(p => p.MatchId)
.Skip(page - 1 * pageSize)
.Take(pageSize)
.ToList();
MatchId
已编入索引。
每场比赛有 10 名玩家,我目前在 PlayerMatch
表中有 330 万场比赛和 3300 万行,但数据正在不断收集。
有没有办法解决 OrderBy 造成的性能大幅下降?
This post 类似,但似乎没有解决。
编辑:
这是生成的 SQL 查询:
SELECT
`Project1`.`AccountId`,
`Project1`.`MatchId`,
`Project1`.`PlayerSlot`,
`Project1`.`HeroId`,
`Project1`.`Item_0`,
`Project1`.`Item_1`,
`Project1`.`Item_2`,
`Project1`.`Item_3`,
`Project1`.`Item_4`,
`Project1`.`Item_5`,
`Project1`.`Kills`,
`Project1`.`Deaths`,
`Project1`.`Assists`,
`Project1`.`LeaverStatus`,
`Project1`.`Gold`,
`Project1`.`GoldSpent`,
`Project1`.`LastHits`,
`Project1`.`Denies`,
`Project1`.`GoldPerMin`,
`Project1`.`XpPerMin`,
`Project1`.`Level`,
`Project1`.`HeroDamage`,
`Project1`.`TowerDamage`,
`Project1`.`HeroHealing`
FROM (SELECT
`Extent2`.`AccountId`,
`Extent2`.`MatchId`,
`Extent2`.`PlayerSlot`,
`Extent2`.`HeroId`,
`Extent2`.`Item_0`,
`Extent2`.`Item_1`,
`Extent2`.`Item_2`,
`Extent2`.`Item_3`,
`Extent2`.`Item_4`,
`Extent2`.`Item_5`,
`Extent2`.`Kills`,
`Extent2`.`Deaths`,
`Extent2`.`Assists`,
`Extent2`.`LeaverStatus`,
`Extent2`.`Gold`,
`Extent2`.`GoldSpent`,
`Extent2`.`LastHits`,
`Extent2`.`Denies`,
`Extent2`.`GoldPerMin`,
`Extent2`.`XpPerMin`,
`Extent2`.`Level`,
`Extent2`.`HeroDamage`,
`Extent2`.`TowerDamage`,
`Extent2`.`HeroHealing`
FROM `match` AS `Extent1` INNER JOIN `playermatch` AS `Extent2` ON `Extent1`.`MatchId` = `Extent2`.`MatchId`
WHERE ((`Extent1`.`GameMode`) = 2) AND ((`Extent1`.`LobbyType`) = 7)) AS `Project1`
ORDER BY
`Project1`.`MatchId` ASC LIMIT 0,1000
【问题讨论】:
【参考方案1】:另一种方法是使用一个 VIEW 来执行连接并索引相应的列,然后创建一个使用 VIEW 并返回仅包含页面数据的 TABLE 的表值函数。 您必须手动编写分页的 SQL 查询,但我认为它会更快。 我还没有尝试过这样的事情,所以我不能确定会有很大的速度提升。
【讨论】:
【参考方案2】:你没有提供足够的信息来帮助你,所以我会建议。 避免 order by 的一种方法是将行存储在已经按顺序排列的表中。我建议'MatchId' 是一个主键和MatchEntities 的聚集索引。这意味着 MatchEntities.MatchId 是按物理排序存储的。如果您切换连接流以先提取已排序的流,然后再提取附加流,则可以避免昂贵的排序。
像这样:
var playerMatches = (from m in context.MatchEntities // note the switch: MatchEntities goes first
join p in context.PlayerMatchEntities
on p.MatchId equals m.MatchId
where m.GameMode == (byte) gameMode
&& m.LobbyType == (byte) lobbyType
select p)
// .OrderBy(p => p.MatchId) // no need for this any more
.Skip(page - 1 * pageSize)
.Take(pageSize)
.ToList();
还可以查看查询计划以了解数据库如何执行查询、正在使用什么类型的连接等。也许您的原始查询根本没有利用排序。
【讨论】:
以上是关于Linq to Entity Paging with large dataset太慢了的主要内容,如果未能解决你的问题,请参考以下文章