SQL 服务器事务复制错误在线索引操作只能在 SQL 服务器的企业版中执行,从 Ent 到 Standard

SQL Server Transaction Replication error Online index operations can only be performed in Enterprise edition of SQL Server from Ent to Standard

我正在 SQL 服务器中的多个数据库设置事务复制,发布者在 SQL Server 2014 Enterprise Edition 上,目标是 SQL Server 2017 Standard。除了 2 个数据库外,所有数据库都运行良好,我遇到的错误 运行 就在将快照应用到这 2 个数据库的订阅者的最后。

"Online index operations can only be performed in Enterprise edition of SQL Server"

我假设这意味着这 2 个数据库在某一时刻应用了索引或更改了 ONLINE=ON?我试图创建没有聚簇索引和非聚簇索引的快照,但也一直遇到错误。

如果这是真的,有没有办法判断数据库中哪些文章的脚本设置为 ONLINE=ON 导致弹出此错误?

我计划在较小的源数据库上使用 ONLINE=OFF 重建完整索引,希望这是解决方法,但我很好奇是否有人知道解决方案。恨不得就因为这个错误而被迫获取企业版!

更新:索引重建并没有让我摆脱错误。有没有一种方法可以在不应用主键索引的情况下进行事务复制?

更新#2:所以报告回来,我切换了数据库类型并截断了日志,然后重新创建了发布并且如果没有相同的错误就不会拍摄快照。然后,我确定了有问题的文章将其从出版物中删除以创建新快照,但错误仍然存​​在。之后,我进行了日志截断和索引重建,并创建了一个全新的发布以及订阅者和目标数据库,但在将快照传递给订阅者时,该数据库仍然出现错误。 (有或没有文章)

所以最后,似乎一旦您在数据库的模式更改、索引等上使用 ONLINE=ON 功能,您就会陷入只能从企业版到企业版的事务复制,除非您开始编辑不推荐、不支持的事务日志的二进制文件,并且在处理大量事务性生产环境时实际上弊大于利。

太棒了!我喜欢这个问题

我们终于有借口深入内部了

I'm assuming this means that those 2 databases have at one point applied indexing or changes with ONLINE=ON?

这是有道理的...

但请记住,“在线索引操作”可以包括多项任务,例如 CREATE/ALTER/DROP INDEX; ALTER TABLE(使用 CLUSTERED 索引选项和更改列添加或删除 UNIQUE 或 PRIMARY KEY 约束)。

am curious if anyone out there knows the solution

对于 第一步,我们需要找到 who/how/which 任务 已在线执行和使用,这导致了此问题。这意味着我们需要找到在线使用的任务并阻止您使用 none-企业版。

注意! 为了便于讨论,我将讨论 CREATE INDEX 但同样的过程可以应用于其他在线任务, 记录在事务日志中。

这可能有点复杂和高级,因为关于我们如何创建索引的信息,没有存储在数据库 tables(元数据)中记得因为它一旦创建就没有 value/uses(通常,因为我们现在发现它可能在这个问题中有价值)。

因此,我们需要从事务日志中提取信息 与事务复制从中提取信息的位置完全相同。

对于此任务,我们将使用未记录的函数 fn_dblog

Q: Is there a way to tell which articles in the database have been scripted with ONLINE=ON

答案是肯定的:-)

让我们从头到尾演示一下

CREATE DATABASE Test
GO
USE Test
GO

DROP TABLE IF EXISTS fyi_links_indexed
GO

Create table fyi_links_indexed(url char(100))
GO -- No index yet

-- Let's find the last LSN from the log file. 
-- This will help us to filter the log file in our sample instead of read the entire log file each time.
SELECT TOP 1 [Current LSN] 
FROM fn_dblog(null,null)
ORDER BY [Current LSN] DESC
GO -- remember this value for next step. In my test Db I got 00000025:00000a18:0024

-- For each query now we will use: where [Current LSN] > '00000025:00000a18:0024'

-- Let's CREATE INDEX ONLINE and check what was added in the transaction log

CREATE INDEX fyi_links_url ON fyi_links_indexed (url)
   WITH (ONLINE = ON);
GO

-- just for understanding let's see waht added to the transaction log:
SELECT * FROM fn_dblog(null,null)
where [Current LSN] > '00000025:00000a18:0024'
GO
-- Notice that creating the index online writes multiple rows in the transaction log


-- just for understanding let's confirm that this index was created ONLINe,
-- which is what the replication see as well
-- and what failed in the standards edidion
SELECT [Current LSN], [Transaction ID], [Transaction Name] FROM fn_dblog(null,null)
where [Current LSN] > '00000025:00000a18:0024' and [Transaction Name] in('CREATE INDEX','ONLINE_INDEX_DDL')
GO


-- our next task is to find the transaction ID
-- search for Transaction name "CREATE INDEX"
SELECT [Transaction ID], [Transaction Name] FROM fn_dblog(null,null)
where [Current LSN] > '00000025:00000a18:0024' and Operation = 'LOP_BEGIN_XACT' and [Transaction Name] = 'CREATE INDEX'
GO -- 0000:0000042d



-- Now we have the transaction ID so we can get the object ID if the entitiy which was used ONLINE (in our case the INDEX)
select [Lock Information]
FROM fn_dblog(null,null) where [Transaction ID] = '0000:0000042d' and [Lock Information] like '%object_id = %'
GO 
-- result should be like:
-- HoBt 0:ACQUIRE_LOCK_SCH_M METADATA: database_id = 9 INDEXSTATS(object_id = 901578250, index_id or stats_id = 2), lockPartitionId = 0
-- Notice the object Id (in my case 901578250)

就这些了!

我们找到了使用 ONLINE 创建的有问题实体的 ID


下一步是什么?

问题是从事务日志中清除信息以便按原样继续复制,可能非常先进和复杂(理论上可以完成)

所以 此时我们知道要修复什么 但下一个问题是如何修复...

最简单的方法是在创建有问题的实体后从这一点开始复制,因为如果我们使用当前的事务日志,那么即使我们现在删除索引也会出现问题,因为复制已完成日志通过日志,一旦我们将使用包含 CREATE INDEX ONLINE 的日志,那么问题将再次出现。

创建复制后,我们需要避免将来出现相关问题

例如,在生产中,索引重建(可以使用 ONLINE)的执行通常是通过手动执行或在 Jobs 中执行的维护任务来完成的(不幸的是,它可能来自其他触发器,如果​​您不熟悉系统)。

此时您必须确认,如果您从源服务器复制了相同的作业,那么您应该修复所有这些作业和其他使用 ONLINE 的任务。

这是一个单独的任务

找到包括在线世界在内的工作

SELECT 
    s.step_id as 'Step ID',
    j.[name] as 'SQL Agent Job Name',
    s.database_name as 'DB Name',
    s.command as 'Command'
FROM   msdb.dbo.sysjobsteps AS s
INNER JOIN msdb.dbo.sysjobs AS j ON  s.job_id = j.job_id
WHERE  s.command LIKE '%ONLINE%'

我们在这里遇到的最后一个问题

Is there a method by chance to do transactional replication without the primary key indexing being applied?

没有。事务复制需要对每个已发布的 table.

进行主键约束

https://docs.microsoft.com/en-us/sql/relational-databases/replication/administration/frequently-asked-questions-for-replication-administrators?view=sql-server-ver15#how-do-i-manage-constraints-on-published-tables---


信用

答案首发于此(原作者复制于此):https://ariely.info/Blog/tabid/83/EntryId/302/SQL-Server-Transaction-Replication-from-Enterprise-to-Standard-error-Online-index-operations-can-only-be-performed-in-Enterprise-edition.aspx