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

Sql server Windows Azure SQL数据库-标识自动增量列跳过值,sql-server,entity-framework,asp.net-mvc-4,entity-framework-5,azure-sql-database,Sql Server,Entity Framework,Asp.net Mvc 4,Entity Framework 5,Azure Sql Database,目前正在使用EntityFramework5开发ASP.NETMVC4应用程序。在初始开发阶段使用CodeFirst。但是现在已经禁用了自动迁移,并直接使用SSM和编写POCO来设计新表。一切正常 最近,在生产中发现了一个奇怪的问题。其中一个最初设计的表中的记录跳过了自动递增标识值900多个数字。在过去3个月内,这种情况发生了3次。已在本地调试应用程序,但无法复制。没有观察到任何模式或趋势 型号: public class Enquiry { [Key] [DatabaseGen

目前正在使用EntityFramework5开发ASP.NETMVC4应用程序。在初始开发阶段使用CodeFirst。但是现在已经禁用了自动迁移,并直接使用SSM和编写POCO来设计新表。一切正常

最近,在生产中发现了一个奇怪的问题。其中一个最初设计的表中的记录跳过了自动递增标识值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; }
}
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();
    }
}
DBContext:

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; }
}
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个数字的大间隙跳过


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

如果您需要消除这些差距,您可能在这里运气不佳

我自己在开发/测试一个新的应用程序时遇到了这个问题。根据我读到的有关SQLServer2012的内容,我可以直观地了解SQLAzure中发生了什么。我还没有找到任何关于SQLAzure的文档

据我所知,这是一个功能,在我看来是一个错误。在Sql server 2012中,Microsoft添加了创建序列的功能。序列记录1000块中使用的值。让我们假设你的序列正在进行。。。1, 2, 3, 4, 5... 然后sql server重新启动。这个序列已经保存了一个事实,1-1000块已经被使用了,所以它会让你跳到下一个1000块。。。。所以你的下一个值是100100210031004。。。。这可以提高使用序列时插入的性能,但可能会导致不寻常的间隙。对于您的序列,有一个解决方案。指定顺序时,请添加“NOCACHE”参数,这样就不会一次保存1000个块

其中一个问题是,标识列似乎已更改为使用相同的范例。因此,当您的服务器重新启动时,或者在本例中,您的sql azure实例重新启动时,您的标识列中可能会出现较大的间隙(1000),因为它正在将大块缓存为“已使用”。对于sql server 2012,有一个解决方案。您可以指定一个启动标志t272,以使用旧的sql server 2008 r2范例将您的标识还原为。问题是我不知道(可能不可能)如何在SQLAzure中指定它。找不到文档

特别是“服务器重新启动或其他故障后的连续值”一节。它是这样说的:

服务器重新启动或其他故障后的连续值–SQL server 可能出于性能原因和某些 在数据库或服务器发生故障时,分配的值可能会丢失 重新启动。这可能导致插入时标识值出现间隙。如果 如果不接受间隙,则应用程序应使用序列 使用NOCACHE选项的生成器或使用自己的机制 生成关键值

因此,如果需要连续值,可以尝试使用nocache指定序列,而不是依赖标识列。我自己也没试过


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

似乎没有针对SQL Azure的TF 272解决方案。我只是在两个表(999和1000之间的间隙)中注意到了这个问题,在检查这两个表并检查插入的记录之前,我认为这是一个安全漏洞。
有关详细信息,请参见的最后一项。这是一种重新保证,但看起来更像是一个bug而不是一个特性。

我也有这个问题,直到现在我还找不到任何方法,似乎实体有一个bug或类似的东西。
我在互联网上搜索,但什么都没有

尝试使用触发式重新播种方法。我相信这会解决问题,并在该链接上看到更多的漫游

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
由于Azure中不支持“DBCC CHECKIDENT”,现在您可以在本例中使用该方法 在那个链接中,我找到了一些解决办法

  • 使用SqlAzure的自动密钥时使用GUID作为密钥
  • 如果整型键与我的情况类似,则让记录插入并返回,然后删除它,并通过使用图灵关闭identity来使用正确的键重新插入它 将identity_insert XXXTable设置为on——这基本上会关闭identity
  • 然后,当我使用正确的键插入时,再次打开标识

    将identity_insert XXXTable设置为off——这基本上打开identity


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

    请看这里:@Rosiek,我没有看到任何好的现成解决方案可以应用于MS Cloud中的SQL Azure Web Edition。我也看到了同样的问题。找到答案了吗?遇到了同样的问题-自动递增的字段值突然增加了1000左右。不仅如此,还收到了一次主键冲突(主键基于自动递增字段)。本地数据库从来没有出现过任何问题。对于经常重启的服务器和很少获取行的表来说,这是一个奇迹!谢谢,我一直在interwebz寻找一个快速而肮脏的