将多行转换为单列

时间:2012-11-30 18:40:23

标签: sql tsql entity-framework-4.1 ef-code-first cursor

我有一个数据库表,UserRewards有超过300万行。在这一行中,有一个userID和每行的rewardID(以及其他字段)。

有一个用户表(拥有大约400万个唯一用户),它有主键userID和其他字段。 出于性能原因,我想将userrewards中每个用户的rewardID移动到用户的连接字段中。 (新的nvarchar(4000)字段名为Rewards) 我需要一个可以尽快完成此任务的脚本。

我有一个游戏使用下面的脚本加入奖励,但它每分钟只处理大约100个用户,这需要太长时间才能获得我拥有的大约400万个唯一用户。

 set @rewards = ( select REPLACE( (SELECT rewardsId AS [data()] from userrewards
 where UsersID = @users_Id and BatchId = @batchId
       FOR XML PATH('')  ), ' ', ',') )

有什么建议可以优化吗?我即将尝试一个while循环,所以看看它是如何工作的,但任何其他的想法都将受到极大的欢迎。

编辑:

我的网站执行以下操作:

我们有大约400万用户被预先分配了5-10个“奖项”。此关系位于userrewards表中。

用户访问该网站,我们识别它们,并在数据库中查找分配给它们的奖励。

问题是,该网站非常受欢迎,因此我有很多人在同一时间访问该网站请求他们的数据。以上将减少我的联接,但我知道这可能不是最好的解决方案。我的数据库服务器在我开始访问网站的10秒内达到100%的CPU使用率,因此大多数人的请求超时(它们显示错误页面),或者他们得到结果,但不是在令人满意的时间。

有人能够为我的问题提出更好的解决方案吗?

2 个答案:

答案 0 :(得分:1)

我认为您尝试的方法是个坏主意有几个原因。首先,您将如何在users表中维护逗号分隔列表?有可能奖励是批量加载的,比如晚上,所以现在这不是一个真正的问题。即便如此,有一天你可能想要更频繁地分配奖励。

其次,当您想要删除奖励或更改其中一个奖励的名称时会发生什么?您需要在两个不同的位置更新信息,而不是更新一个表。

如果您有400万用户,并且有数千个并发访问,那么由于时间原因引起的小的不一致将会引起注意,并可能引起用户投诉。首席执行官打电话询问为什么投诉增加可能不是你想要处理的事情。

另一种方法是在UserRewards(UserId,BatchId,RewardsId)上构建索引。据推测,每个字段都是几个字节,因此3000万条记录应该很容易适应8 GB的内存(确保SQL Server几乎分配了所有内存!)。您希望的查询可以通过此索引严格满足,而无需将UserRewards表带入内存。因此,只需要缓存索引。并且,它将针对此查询进行优化。

可能减慢一切的一件事是分配奖励的频率。如果以甚至10%的读取速率分配这些,则可以使插入/更新阻止读取。您希望使用READ_NOLOCK执行查询,以避免此问题。您还需要确保在记录或页面级别发生锁定,以避免与读取冲突。

答案 1 :(得分:0)

可能为时已晚,但使用uniqueidentifiers作为键不仅会使存储空间翻两番(与使用int作为键相比),但会使查询速度降低几个数量级。避免!!!