Windows Azure SQL数据库 - 标识自动增量列会跳过值

时间:2013-06-09 17:35:08

标签: sql-server entity-framework asp.net-mvc-4 entity-framework-5 azure-sql-database

目前正在使用Entity Framework 5处理ASP.Net MVC 4应用程序。使用CodeFirst进行初始开发阶段。但现在已禁用自动迁移并直接使用SSMS设计新表并编写POCO。一切都很好。

最近,在Production中发现了一个奇怪的问题。其中一个最初设计的表中的记录跳过自动增量标识值超过900个数字。这在过去3个月内发生了3次。在本地调试应用程序但无法重现。没有观察到任何模式或趋势。

型号:

public class Enquiry
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public Int64 EnquiryId { get; set; }

    [Required]
    public int UserId { get; set; }

    [Required]
    public byte Bid { get; set; }

    ...

    [Required]
    public DateTime Created { get; set; }

    [Required]
    public DateTime Modified { get; set; }
}

public class EnquiryDetail
{
    [Key]
    public Int64 EnquiryId { get; set; }

    [Required]
    public int CreditScore { get; set; }

    [Required]
    public byte BidMode { get; set; }

    public virtual Enquiry Enquiry { get; set; }
}

的DbContext:

public class EscrowDb : DbContext
{

    public EscrowDb()
        : base("name=DefaultConnection")
    {

    }
    public DbSet<Enquiry> Enquiries { get; set; }
    public DbSet<EnquiryDetail> EnquiryDetails { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        modelBuilder.Entity<EnquiryDetail>()
            .HasRequired<Enquiry>(ed => ed.Enquiry)
            .WithRequiredDependent(e => e.EnquiryDetail);
    }
}

控制器:

[Authorize]
public class EnquiryController : Controller
{
    private EscrowDb _db = new EscrowDb();

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create(EnquiryViewModel core)
    {
       var enquiry = new Enquiry();
       // Some code to set properties using passed ViewModel
       ...

       var enquiryDetail = new EnquiryDetail();
       // Some code to set properties using passed ViewModel
       ...

       enquiry.EnquiryDetail = enquiryDetail;

       _db.Enquiries.Add(enquiry);
       _db.SaveChanges();
    }
}

到目前为止,所有这些代码都运行良好,除了偶然跳过近1000个数字的大间隙的身份值。

有人遇到过这样的问题吗?请分享您的想法。

4 个答案:

答案 0 :(得分:19)

如果你需要消除这些差距,你可能会失去运气。

在开发/测试新应用程序时,我自己就遇到了这个问题。我根据我读到的有关sql server 2012的内容,直观地了解sql azure中发生的事情。我无法找到有关sql azure的任何文档。

据我所知,这是一个IMO错误的功能。在Sql server 2012中,Microsoft添加了创建序列的功能。序列记录1000块中使用的值。所以假设您的序列正在进行中...... 1,2,3,4,5 ...然后您的sql server重新启动。那么序列已经保存了块1-1000已被使用的事实,所以它会跳到你的下一个1000 ....所以你的下一个值是1001,1002,1003,1004 ....这提高了性能使用序列时插入,但可能导致异常间隙。您的序列有一个解决方案。指定序列时,添加“NOCACHE”参数,以便一次不保存1000个块。 See here for more documentation.

如果这成为一个问题,那么Identity列似乎已被更改为使用相同的范例。因此,当您的服务器,或者在这种情况下,您的sql azure实例重新启动时,您可以在标识列中获得较大的间隙(1000),因为它将大块缓存为“已使用”。对于sql server 2012,有一个解决方案。您可以指定启动标志t272以将您的身份恢复为使用旧的sql server 2008 r2范例。问题是我不知道(可能不可能)如何在sql Azure中指定它。找不到文档。 See this thread for more details on sql server 2012.

Check the documentation of identity here in the msdn.特别是“服务器重启或其他故障后的连续值”部分。以下是它的说法:

  

服务器重启或其他故障后的连续值 -SQL Server   可能因性能原因和某些原因而缓存身份值   在数据库故障或服务器期间,分配的值可能会丢失   重新开始。这可能导致插入时身份值的缺口。如果   差距是不可接受的,然后应用程序应使用序列   生成器使用NOCACHE选项或使用自己的机制来实现   生成关键值。

因此,如果您需要具有连续值,则可以尝试使用nocache指定序列,而不是依赖于您的标识列。我自己没试过,but sounds like you'll have trouble getting this to work with entity framework.

很抱歉,如果这没有多大帮助,但至少它是您的体验的一些信息。

答案 1 :(得分:1)

尝试使用触发方法重新播种。我相信这应该解决它example of its use并在该链接上看到更多的解决方法。

USE [TEST]

CREATE TABLE TEST(ID INT IDENTITY(1,1),VAL VARCHAR(10))

CREATE TRIGGER TGR_TEST_IDENTITY ON TEST
FOR INSERT
AS
DECLARE @RESEEDVAL INT
SELECT @RESEEDVAL = MAX(ID) FROM TEST
DBCC CHECKIDENT('TEST', RESEED, @RESEEDVAL)

INSERT INTO TEST(VAL)VALUES('a')

SELECT * FROM TEST

因为&#39; DBCC CHECKIDENT&#39;现在您可以使用此link中的方法在Azure中不受支持 在那个链接中我得到了一些工作

  1. 使用SqlAzure的自动键时使用GUID作为键
  2. 如果像我的情况那样的整数键让记录插入并返回并删除它,并通过Turing off identity与右键重新插入 设置identity_insert XXXTable on - 这基本上会关闭IDENTITY
  3. 然后当我使用

    插入右键时再次返回身份

    设置identity_insert XXX关闭 - 这基本上打开IDENTITY

    注意:对于正在接收大量插入请求的表而言,这不是一个好的解决方案,但对于寻找临时出路的人可能会有用

答案 2 :(得分:0)

似乎没有TF 272可以解决SQL Azure问题。我刚刚注意到2个表中的问题(999和1000的间隙),并且在检查两个表并检查插入的记录之前认为这是一个安全漏洞。 有关详细信息,请参阅this MS TechNet discussion的最后一项。有点重新保证,但看起来更像是一个错误,而不是一个功能。

答案 3 :(得分:0)

我也有这个问题,直到这次我找不到任何方式,似乎实体有一个bug或类似的东西。 我在互联网上搜索但没有任何内容