为什么Sql Server SELECT不返回所有条目?

时间:2018-09-18 21:54:32

标签: sql-server

好的。我完全重写了我的问题。

数据库表

CREATE TABLE [dbo].[IntegrationCommandLog](
    [Id] [uniqueidentifier] NOT NULL,
    [Content] [nvarchar](max) NULL,
    [OrderingKey] [bigint] IDENTITY(1,1) NOT NULL,
    [RowVersion] [timestamp] NULL,
    [Topic] [nvarchar](13) NULL,
 CONSTRAINT [PK_IntegrationCommandLog] PRIMARY KEY NONCLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

CREATE CLUSTERED INDEX [IX_IntegrationCommandLog_OrderingKey] ON [dbo].[IntegrationCommandLog]
(
    [OrderingKey] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO

复制者。无需附加调试器即可运行发行版

必需的软件包:

Install-Package Dapper
Install-Package System.Data.SqlClient

代码:

using Dapper;
using System;
using System.Data.SqlClient;
using System.Linq;
using System.Threading.Tasks;

namespace TestApp
{
    class Program
    {
        private const string Sql = "SELECT * FROM dbo.IntegrationCommandLog WHERE OrderingKey > @OrderingKey ORDER BY OrderingKey";
        private const string cs = "Data Source=.;Initial Catalog=Test;Integrated Security=True";

        static void Main(string[] args)
        {
            Task.Run(() => Query());

            var tasks = new Task[200];
            for (int i = 0; i < tasks.Length; ++i)
                tasks[i] = Task.Run(() => Insert());

            while (true)
            {
                int j = Task.WaitAny(tasks);
                tasks[j] = Task.Run(() => Insert());
            }
        }

        private async static Task Query()
        {
            long last = -1;
            var connection = new SqlConnection(cs);
            await connection.OpenAsync();
            while (true)
            {
                var entries = await connection.QueryAsync<IntegrationLogEntry>(Sql, new { OrderingKey = last });

                Console.WriteLine(entries.Count());
                if (entries.Any())
                {
                    last = entries.Aggregate((e1, e2) =>
                    {
                        if (e1.OrderingKey + 1 != e2.OrderingKey)
                            Console.WriteLine($"Sequence violation {e1.OrderingKey} {e2.OrderingKey}");

                        return e2;
                    }).OrderingKey;
                }
                await Task.Delay(1000);
            }
        }

        private static async Task Insert()
        {
            string sql = @"SET NOCOUNT ON;
INSERT INTO [dbo].[IntegrationCommandLog] ([Id], [Content], [Topic])
VALUES ( @Id, @Content, @Topic);
SELECT [OrderingKey], [RowVersion]
FROM [dbo].[IntegrationCommandLog]
WHERE @@ROWCOUNT = 1 AND [Id] = @Id";

            var content = new string('a', 1000);
            using (var connection = new SqlConnection(cs))
            {
                await connection.OpenAsync();
                await connection.ExecuteAsync(sql, new { Id = Guid.NewGuid(), Content = content, Topic = "SomeTopic" });
            }
        }
    }

    public class IntegrationLogEntry
    {
        public Guid Id { get; private set; }
        public string Content { get; private set; }
        public string Topic { get; private set; }
        public long OrderingKey { get; private set; }
        public byte[] RowVersion { get; set; }
    }
}

确保没有空隙

SELECT top 100 * FROM (SELECT *, rowid = ROW_NUMBER() OVER (ORDER BY OrderingKey) FROM [dbo].[IntegrationCommandLog]) l1
JOIN (SELECT *, rowid = ROW_NUMBER() OVER (ORDER BY OrderingKey) FROM [dbo].[IntegrationCommandLog]) l2 on l1.rowid + 1 = l2.rowid
WHERE l1.OrderingKey + 1 != l2.OrderingKey

输出

Console output

  

Microsoft SQL Server 2016(SP1)(KB3182545)-13.0.4001.0(X64)2016年10月28日18:17:30版权所有(c)Windows Server 2016 Datacenter 6.3(Build 14393)上的Microsoft Corporation Developer Edition(64位) :)(管理程序)

问题:

  1. 为什么查询不返回所有条目?
  2. 如何获取正确的条目列表?

1 个答案:

答案 0 :(得分:0)

e1.OrderingKey +1!= e2.OrderingKey测试e2仅比前一个密钥高1。数据库无法保证。

很多情况会导致非连续的身份:(不要忘记删除)

https://docs.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property?view=sql-server-2017

  

交易中的连续值–插入交易   多行不能保证获得行的连续值   因为其他并发插入可能会在表上发生。如果值   必须是连续的,则交易应使用排他锁   或使用SERIALIZABLE隔离级别。

     

服务器重启或其他故障后的连续值– SQL Server可能会缓存   出于性能原因和一些已分配的标识值   数据库故障或服务器重新启动期间,这些值可能会丢失。这个   插入时可能会导致身份值出现空白。如果没有差距   接受,那么应用程序应使用自己的机制   生成键值。将序列生成器与NOCACHE一起使用   选项可以将差距限制为从未提交的事务。

     

值的重用–对于具有特定标识的给定标识属性   种子/增量,标识值不会被引擎重用。如果一个   特定的插入语句失败或插入语句已滚动   然后,消耗的身份值将丢失,并且不会   再次产生。这可能会导致在后续标识时出现空白   值生成。

相关问题