SQL 服务器 CE @threshold 和身份范围到底发生了什么?
SQL Server CE what is really happening with @threshold and identity ranges?
伙计们,因为这个问题与 IDENTITY 列和合并复制有关,请不要回答 "use GUIDs instead"。我敏锐地意识到两者的优点和局限性,并且从 SQL Server 2000 开始就一直使用 CE 的 SQL 复制。偶尔我会感到惊讶。就是这样一个案例。
问题描述比较复杂,请多多包涵。
以下是此处 https://msdn.microsoft.com/en-us/library/ms152543.aspx 的摘录,是我一直以来对身份范围和阈值的理解。
"Subscribers running SQL Server Compact or previous versions of SQL Server are assigned only the primary range; assignment of new ranges is controlled by the @threshold parameter. Additionally, a republishing Subscriber has only the range specified in the @identity_range parameter; it must use this range for local changes and for changes at Subscribers that synchronize with the republishing Subscriber. For example, you could specify 10000 for @pub_identity_range, 500000 for @identity_range and 80 percent for @threshold. After 8000 inserts at a Subscriber (80 percent of 10000), the Publisher is assigned a new range. When a new range is assigned, there will be a gap in the identity range values in the table. Specifying a higher threshold results in smaller gaps, but the system is less fault-tolerant: if the Merge Agent cannot run for some reason, a Subscriber could more easily run out of identities."
如果我们暂时假设这是真的,那么我们将开始解决我的问题。
为了帮助用户使用我们的应用程序,我们一直在使用以下查询的变体,让客户知道如果他们继续使用,他们可能 运行 失去身份,并启动同步以获得新的范围。
SELECT
AUTOINC_MAX, AUTOINC_NEXT, AUTOINC_MAX-AUTOINC_NEXT
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME = N'Asset'
AUTOINC_MAX | AUTOINC_NEXT | AUTOINC_MAX-AUTOINC_NEXT
------------+--------------+-------------------------
3081898 | 3080899 | 999
通过评估 AUTOINC_MAX - AUTOINC_NEXT
(= 999) 我们可以看到 ID 何时不足
在代码中,我们正在查看 AUTOINC_MAX - AUTOINC_MIN
,它给出了分配的范围。使用默认阈值 80% 和剩余范围,我们可以建议客户端在看起来 运行 结束时进行同步。
然而,这就是我认为正确的地方在实践中失败了。参考上面的微软细节,这句话脱颖而出 "When a new range is assigned, there will be a gap in the identity range values in the table."
我认为这是以下意思
如果我们的用户具有 0-1000 ID 的身份范围并且使用的 ID 最多为 801。在下一次同步时,将为用户分配下一个范围 1001-2000(我们假设一个订阅者用于说明)。作为同步的结果,下一个使用的 ID 将是 1001,与 802-1000 之间存在差距。
如果我的理解有误,请先告诉我。
其次,这不是我们在实践中看到的。
在实践中,根据上面的示例,post 同步和后续插入是我们所使用的 ID 的余额,直到我们完全扩展原始范围。然后在扩展范围后,AUTOINC-MIN、-MAX 和-NEXT 都更新到新范围。没有发生其他同步。
下面是一个例子。
在目标 table 中最后使用的 ID 是 3080899
为了模拟使用,使用了以下查询
INSERT INTO Asset (lInstID, lTypeID, sUsrName, lUsrID, dCreated, dAudit, sStatus)
SELECT
lInstID, lTypeID, sUsrName, lusrID, dCreated, dAudit, sStatus
FROM
Asset
WHERE
lAssetID = 3080899
插入后使用的下一个 ID 值是 3080900(如预期,例如 AUTOINC_NEXT = 3080899,+ 1 = 3080900)
我们重复此插入,直到达到分配的标识范围的 80%。
SELECT
AUTOINC_MAX, AUTOINC_NEXT, AUTOINC_MAX-AUTOINC_NEXT
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME = N'Asset'
AUTOINC_MAX | AUTOINC_NEXT | AUTOINC_MAX-AUTOINC_NEXT
------------+--------------+-------------------------
3081898 | 3081699 | 199
我们同步。我们注意到 800 个订阅者更改。我们查询,这就是我们所看到的。与预同步相比没有变化。
AUTOINC_MAX | AUTOINC_NEXT | AUTOINC_MAX-AUTOINC_NEXT
------------+--------------+-------------------------
3081898 | 3081699 | 199
我们继续插入直到剩下零个 ID
AUTOINC_MAX | AUTOINC_NEXT | AUTOINC_MAX-AUTOINC_NEXT
------------+--------------+-------------------------
3081898 | 3081898 | 0
再插入一次,结果是这样的
AUTOINC_MAX | AUTOINC_NEXT | AUTOINC_MAX-AUTOINC_NEXT
------------+--------------+-------------------------
3082898 | 3081899 | 999
这是完全出乎意料的,并且与 相反,当分配新的范围时,table 中的身份范围值将存在差距。 实际上身份范围是连续的。这有点可取,因为我们不会浪费 ID。
我在 .SDF
中找不到存储下一个分配范围的位置。
我假设它是来自 sysmergearticles
服务器 table 的 next_range_start
和 next_range_end
,但是找不到在 .SDF
中公开这些值的文档].
如果有人知道这里发生了什么,我将不胜感激。
请注意,如果您在没有同步数据库的情况下完全扩展此 "next range",则会出现预期的错误 returns。
同步 post 错误显示订阅者上传了 1200 条新记录(之前范围的 200 条加上 "next range" 的 1000 条)
AUTOINC_MAX | AUTOINC_NEXT | AUTOINC_MAX-AUTOINC_NEXT
------------+--------------+-------------------------
3083898 | 3082898 | 999
亲切的问候
安德鲁
对于那些感兴趣的人,我从微软的一个小伙子那里收到了这个答案。
Hi Andrew,
Based on testing, I believe this should be a document bug. The CE
synchronization should use same method subscriber running SQL Server
2005 or a later version. That is,
subscriber will receive two identity ranges. The secondary range is
equal in size to the primary range; when the primary range is
exhausted, the secondary range is used, and the Merge Agent assigns a
new range to the Subscriber. The new range becomes the secondary
range, and the process continues as the Subscriber uses identity
values.
So, let us say, you set subscriber identity range to 10. Then the
publisher starts from 1 to 11 for primary range and 11 to 21 for the
secondary range. And subscriber starts from 21 to 31 for the primary
range and 31 to 41 for the secondary range. If there is no
synchronization before you consume all subscriber range, you will hit
the error, it means you could insert double number record of
subscriber range you set to subscriber database before you hit the
error message.
For publisher end, if you consume all range but not in a single batch,
insert trigger will help you re-allocate a new range. For example,
before synchronization, if publisher end reaches 21 and next insert
will start from 42 since 22 to 41 belongs to subscriber.
The mechanism is the same for multiple subscribers, if you are still
in primary range for subscriber, new range will not be allocated. If
you are already in the secondary range, new range will be allocated
and makes your secondary range to new primary and the new range to the
new secondary range.
You could skip re-publisher scenario since CE subscriber could not act
as publisher.
Best regards,
Peter https://social.msdn.microsoft.com/profile/sql%20team%20-%20msft/?ws=usercard-mini
这恰恰证实了我们在测试中看到的情况。所以要明确 SQL CE 3.1+ 确实在第一次同步时接收到主要和次要范围。扩展第一个范围后,次要范围成为主要范围,下一次同步将应用新的次要范围。
只需要查询来确定次要范围在 SQL CE...
伙计们,因为这个问题与 IDENTITY 列和合并复制有关,请不要回答 "use GUIDs instead"。我敏锐地意识到两者的优点和局限性,并且从 SQL Server 2000 开始就一直使用 CE 的 SQL 复制。偶尔我会感到惊讶。就是这样一个案例。
问题描述比较复杂,请多多包涵。
以下是此处 https://msdn.microsoft.com/en-us/library/ms152543.aspx 的摘录,是我一直以来对身份范围和阈值的理解。
"Subscribers running SQL Server Compact or previous versions of SQL Server are assigned only the primary range; assignment of new ranges is controlled by the @threshold parameter. Additionally, a republishing Subscriber has only the range specified in the @identity_range parameter; it must use this range for local changes and for changes at Subscribers that synchronize with the republishing Subscriber. For example, you could specify 10000 for @pub_identity_range, 500000 for @identity_range and 80 percent for @threshold. After 8000 inserts at a Subscriber (80 percent of 10000), the Publisher is assigned a new range. When a new range is assigned, there will be a gap in the identity range values in the table. Specifying a higher threshold results in smaller gaps, but the system is less fault-tolerant: if the Merge Agent cannot run for some reason, a Subscriber could more easily run out of identities."
如果我们暂时假设这是真的,那么我们将开始解决我的问题。
为了帮助用户使用我们的应用程序,我们一直在使用以下查询的变体,让客户知道如果他们继续使用,他们可能 运行 失去身份,并启动同步以获得新的范围。
SELECT
AUTOINC_MAX, AUTOINC_NEXT, AUTOINC_MAX-AUTOINC_NEXT
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME = N'Asset'
AUTOINC_MAX | AUTOINC_NEXT | AUTOINC_MAX-AUTOINC_NEXT
------------+--------------+-------------------------
3081898 | 3080899 | 999
通过评估 AUTOINC_MAX - AUTOINC_NEXT
(= 999) 我们可以看到 ID 何时不足
在代码中,我们正在查看 AUTOINC_MAX - AUTOINC_MIN
,它给出了分配的范围。使用默认阈值 80% 和剩余范围,我们可以建议客户端在看起来 运行 结束时进行同步。
然而,这就是我认为正确的地方在实践中失败了。参考上面的微软细节,这句话脱颖而出 "When a new range is assigned, there will be a gap in the identity range values in the table."
我认为这是以下意思
如果我们的用户具有 0-1000 ID 的身份范围并且使用的 ID 最多为 801。在下一次同步时,将为用户分配下一个范围 1001-2000(我们假设一个订阅者用于说明)。作为同步的结果,下一个使用的 ID 将是 1001,与 802-1000 之间存在差距。
如果我的理解有误,请先告诉我。
其次,这不是我们在实践中看到的。
在实践中,根据上面的示例,post 同步和后续插入是我们所使用的 ID 的余额,直到我们完全扩展原始范围。然后在扩展范围后,AUTOINC-MIN、-MAX 和-NEXT 都更新到新范围。没有发生其他同步。
下面是一个例子。
在目标 table 中最后使用的 ID 是 3080899
为了模拟使用,使用了以下查询
INSERT INTO Asset (lInstID, lTypeID, sUsrName, lUsrID, dCreated, dAudit, sStatus)
SELECT
lInstID, lTypeID, sUsrName, lusrID, dCreated, dAudit, sStatus
FROM
Asset
WHERE
lAssetID = 3080899
插入后使用的下一个 ID 值是 3080900(如预期,例如 AUTOINC_NEXT = 3080899,+ 1 = 3080900)
我们重复此插入,直到达到分配的标识范围的 80%。
SELECT
AUTOINC_MAX, AUTOINC_NEXT, AUTOINC_MAX-AUTOINC_NEXT
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME = N'Asset'
AUTOINC_MAX | AUTOINC_NEXT | AUTOINC_MAX-AUTOINC_NEXT
------------+--------------+-------------------------
3081898 | 3081699 | 199
我们同步。我们注意到 800 个订阅者更改。我们查询,这就是我们所看到的。与预同步相比没有变化。
AUTOINC_MAX | AUTOINC_NEXT | AUTOINC_MAX-AUTOINC_NEXT
------------+--------------+-------------------------
3081898 | 3081699 | 199
我们继续插入直到剩下零个 ID
AUTOINC_MAX | AUTOINC_NEXT | AUTOINC_MAX-AUTOINC_NEXT
------------+--------------+-------------------------
3081898 | 3081898 | 0
再插入一次,结果是这样的
AUTOINC_MAX | AUTOINC_NEXT | AUTOINC_MAX-AUTOINC_NEXT
------------+--------------+-------------------------
3082898 | 3081899 | 999
这是完全出乎意料的,并且与 相反,当分配新的范围时,table 中的身份范围值将存在差距。 实际上身份范围是连续的。这有点可取,因为我们不会浪费 ID。
我在 .SDF
中找不到存储下一个分配范围的位置。
我假设它是来自 sysmergearticles
服务器 table 的 next_range_start
和 next_range_end
,但是找不到在 .SDF
中公开这些值的文档].
如果有人知道这里发生了什么,我将不胜感激。
请注意,如果您在没有同步数据库的情况下完全扩展此 "next range",则会出现预期的错误 returns。
同步 post 错误显示订阅者上传了 1200 条新记录(之前范围的 200 条加上 "next range" 的 1000 条)
AUTOINC_MAX | AUTOINC_NEXT | AUTOINC_MAX-AUTOINC_NEXT
------------+--------------+-------------------------
3083898 | 3082898 | 999
亲切的问候
安德鲁
对于那些感兴趣的人,我从微软的一个小伙子那里收到了这个答案。
Hi Andrew,
Based on testing, I believe this should be a document bug. The CE synchronization should use same method subscriber running SQL Server 2005 or a later version. That is,
subscriber will receive two identity ranges. The secondary range is equal in size to the primary range; when the primary range is exhausted, the secondary range is used, and the Merge Agent assigns a new range to the Subscriber. The new range becomes the secondary range, and the process continues as the Subscriber uses identity values.
So, let us say, you set subscriber identity range to 10. Then the publisher starts from 1 to 11 for primary range and 11 to 21 for the secondary range. And subscriber starts from 21 to 31 for the primary range and 31 to 41 for the secondary range. If there is no synchronization before you consume all subscriber range, you will hit the error, it means you could insert double number record of subscriber range you set to subscriber database before you hit the error message.
For publisher end, if you consume all range but not in a single batch, insert trigger will help you re-allocate a new range. For example, before synchronization, if publisher end reaches 21 and next insert will start from 42 since 22 to 41 belongs to subscriber.
The mechanism is the same for multiple subscribers, if you are still in primary range for subscriber, new range will not be allocated. If you are already in the secondary range, new range will be allocated and makes your secondary range to new primary and the new range to the new secondary range.
You could skip re-publisher scenario since CE subscriber could not act as publisher.
Best regards,
Peter https://social.msdn.microsoft.com/profile/sql%20team%20-%20msft/?ws=usercard-mini
这恰恰证实了我们在测试中看到的情况。所以要明确 SQL CE 3.1+ 确实在第一次同步时接收到主要和次要范围。扩展第一个范围后,次要范围成为主要范围,下一次同步将应用新的次要范围。
只需要查询来确定次要范围在 SQL CE...