在 DATETIME2 列上使用 SYSDATETIME() 默认值的重复键
Duplicate key with SYSDATETIME() default on DATETIME2 column
我有一个使用 ADODB 和 sqloledb 提供程序连接到 SQL Server 2012 的经典 ASP 站点。当用户单击 link 时,我正在向其中插入一条记录a table 来跟踪点击次数。 table 有一个由三列组成的主键:id [int]、clickTime [datetime2(7)] 和 remoteAddress [varchar(15)]。我的插入语句提供了 id 和 remoteAddress 值,clickTime 列设置为默认的 SYSDATETIME()。一个例子是:
INSERT MyClick (id, remoteAddress) VALUES (766319,'108.178.236.50')
我每天捕获几千次点击,但每天都会收到一些重复键的错误。这是一个例子:
Violation of PRIMARY KEY constraint 'PK_MyClick_1'. Cannot insert
duplicate key in object 'dbo.MyClick'. The duplicate key value is
(766319, 2016-01-20 15:30:14.1570772, 108.178.236.50).
在流量相对较小、密钥中包含用户 IP 地址以及 datetime2 极其精确的情况下,我无法理解为什么我仍然偶尔会得到重复的密钥。我知道我可以向密钥添加标识或 GUID 列以保证唯一性。我也明白,如果插入失败,我可以重试插入。但是,我真的很想了解这一点:
在我的场景中如何获得重复的密钥?
编辑:我弄明白了为什么该网站试图插入两条相似的记录(对于相同的 ID 和 remoteAddress)。它源于多年前为解决弹出窗口阻止程序破坏我们网站的问题而构思不当的尝试。该页面有一个 <a>
标记环绕着 <div>
标记。 <a>
标记使用 _blank 目标打开页面,<div>
有一个 onClick 事件,该事件使用 window.open 在新的 window 中打开同一页面。这个 onClick 通常被弹出窗口拦截器拦截,所以只有一个页面会按预期打开。但是如果用户允许站点弹出窗口(或使用没有弹出窗口阻止的浏览器),它实际上会在两个不同的选项卡中打开同一个页面。两个页面都试图插入数据库记录,如果它们足够接近,就会发生重复键错误。我在数据库中发现的是,我们有很多几乎重复的记录,相隔几分之一秒。因此,如果我将网站修复为无法在两个不同的 windows 中打开页面,我相信这个重复的问题将会消失(即使它在技术上仍然是可能的)。感谢那些提供建议帮助我解决问题的人。
这里有两个问题。
首先是即使 datetime2 数据类型的精度,SQL 服务器也可以插入多个具有相同值的记录。在插入 100,000 条记录并将 datetime2 列设置为 sysdatetime() 的循环中,我只得到 1,285 个唯一值。在 datetime2 列中有多达 128 条具有相同值的记录,所以要么我的数据库服务器功能强大到可以极其高效地插入记录,要么 sysdatetime() 函数的准确性并不完全符合人们的预期。无论哪种方式,您都不能简单地依赖 sysdatetime() 来获取唯一值。
但是,我的密钥中有另外两列(包括用户的 IP 地址)时,我会得到重复的密钥,这似乎仍然很奇怪。这将表明具有相同 IP 地址的两个人碰巧在同一时间查看完全相同的数据(有数千种可能性)。事实证明,对于不阻止弹出窗口的浏览器,所请求的网页同时在两个不同的选项卡中打开。这通常会在数据库中产生一对 datetime2 值略有不同的记录,但偶尔会在两个页面加载足够接近时产生重复键。网页我改正了,完全没有重复了。
感谢@JuanCarlosOropeza 帮助思考问题。
我有一个使用 ADODB 和 sqloledb 提供程序连接到 SQL Server 2012 的经典 ASP 站点。当用户单击 link 时,我正在向其中插入一条记录a table 来跟踪点击次数。 table 有一个由三列组成的主键:id [int]、clickTime [datetime2(7)] 和 remoteAddress [varchar(15)]。我的插入语句提供了 id 和 remoteAddress 值,clickTime 列设置为默认的 SYSDATETIME()。一个例子是:
INSERT MyClick (id, remoteAddress) VALUES (766319,'108.178.236.50')
我每天捕获几千次点击,但每天都会收到一些重复键的错误。这是一个例子:
Violation of PRIMARY KEY constraint 'PK_MyClick_1'. Cannot insert duplicate key in object 'dbo.MyClick'. The duplicate key value is (766319, 2016-01-20 15:30:14.1570772, 108.178.236.50).
在流量相对较小、密钥中包含用户 IP 地址以及 datetime2 极其精确的情况下,我无法理解为什么我仍然偶尔会得到重复的密钥。我知道我可以向密钥添加标识或 GUID 列以保证唯一性。我也明白,如果插入失败,我可以重试插入。但是,我真的很想了解这一点:
在我的场景中如何获得重复的密钥?
编辑:我弄明白了为什么该网站试图插入两条相似的记录(对于相同的 ID 和 remoteAddress)。它源于多年前为解决弹出窗口阻止程序破坏我们网站的问题而构思不当的尝试。该页面有一个 <a>
标记环绕着 <div>
标记。 <a>
标记使用 _blank 目标打开页面,<div>
有一个 onClick 事件,该事件使用 window.open 在新的 window 中打开同一页面。这个 onClick 通常被弹出窗口拦截器拦截,所以只有一个页面会按预期打开。但是如果用户允许站点弹出窗口(或使用没有弹出窗口阻止的浏览器),它实际上会在两个不同的选项卡中打开同一个页面。两个页面都试图插入数据库记录,如果它们足够接近,就会发生重复键错误。我在数据库中发现的是,我们有很多几乎重复的记录,相隔几分之一秒。因此,如果我将网站修复为无法在两个不同的 windows 中打开页面,我相信这个重复的问题将会消失(即使它在技术上仍然是可能的)。感谢那些提供建议帮助我解决问题的人。
这里有两个问题。
首先是即使 datetime2 数据类型的精度,SQL 服务器也可以插入多个具有相同值的记录。在插入 100,000 条记录并将 datetime2 列设置为 sysdatetime() 的循环中,我只得到 1,285 个唯一值。在 datetime2 列中有多达 128 条具有相同值的记录,所以要么我的数据库服务器功能强大到可以极其高效地插入记录,要么 sysdatetime() 函数的准确性并不完全符合人们的预期。无论哪种方式,您都不能简单地依赖 sysdatetime() 来获取唯一值。
但是,我的密钥中有另外两列(包括用户的 IP 地址)时,我会得到重复的密钥,这似乎仍然很奇怪。这将表明具有相同 IP 地址的两个人碰巧在同一时间查看完全相同的数据(有数千种可能性)。事实证明,对于不阻止弹出窗口的浏览器,所请求的网页同时在两个不同的选项卡中打开。这通常会在数据库中产生一对 datetime2 值略有不同的记录,但偶尔会在两个页面加载足够接近时产生重复键。网页我改正了,完全没有重复了。
感谢@JuanCarlosOropeza 帮助思考问题。