1

我正在使用 MySQL 和实体框架在 ASP.NET / C# 中开发一个 webapp。我想使用一些计数器列,它们会通过增加它们的值 +1 来经常更新。我有一个计数器列所在的产品表。我有两个问题:

1) 我应该为柜台使用第二张桌子吗?- 主产品表会被频繁读取,如果我非常频繁地更新行会损害性能,因为每次更新计数器时行都会被锁定(我使用 InnoDB)

2) 使用 MySQL 和 Entity Framework 对一行进行 +1 增量的最佳方法是什么。我不介意计数器 100% 准确,所以如果有一些更新冲突,我可以捕捉到它们,但我可以在没有更新的情况下通过。我认为大多数更新将很快完成并包含在更新中。

我正在添加一些我用来通过利用静态变量来防止频繁写入数据库的代码来实现这一点。

代码:

if (Global.DataCounters != null)
    {
        if (Global.DataCounters.ContainsKey(id))
        {
            int new_value = ++Global.DataCounters[id];
            Global.DataCounters.Remove(id);
            Global.DataCounters.Add(id, new_value);

            // check datatime

            if ((DateTime.Now - Global.LastFlushed).Minutes > 10)
            {
                // update counter in db and reset data

                Global.LastFlushed = DateTime.Now;
            }
        }
        else
        {
            // first time view of a device, set to zero views
            Global.DataCounters.Add(id, 1);
        }

    }
    else
    {
        Global.DataCounters = new Dictionary<int, int>();
    }

全球.asax:

public static Dictionary<int, int> DataCounters = new Dictionary<int,int>();
public static DateTime LastFlushed;

void Application_Start(object sender, EventArgs e)
{
    LastFlushed = DateTime.Now;
    RegisterRoutes(System.Web.Routing.RouteTable.Routes);
}

你认为这是一个很好的实现吗?

谢谢

4

1 回答 1

1

仅当重要的产品表读取(例如 > 50%)不需要计数器信息时,计数器的第二个表才会有帮助。否则,您总是会加入两个表,从而使您的读取变得昂贵。

基于MySQL doc:对于更新计数器,如果您的 WHERE 条件使用唯一索引来搜索唯一行(要更新),那么只会采用行级锁(并且不会采用间隙锁)。对于您的情况,这将是最好的方案(假设产品 ID 可以用作唯一索引)。我会建议使用 Entity SQL 来触发 Update 语句(或调用会执行相同操作的 SP)。

如果您只想使用实体术语(没有 EntitySQL 或 SP),那么不要对这个特定操作使用事务范围 - 这样,用于获取产品实体的选择不会锁定,并且SaveChanges将是单个更新语句递增计数器。当然,在事务之外使用两个语句意味着更新可能会失败(假设您有一些可用于乐观并发检查的时间戳列),但您已表明它是可以接受的。

最后,如果在递增计数器时事务是不可避免的,则尝试使它们更短,并尝试使用较低的隔离级别,例如Read Committed.

于 2013-01-22T06:15:34.960 回答