Вставки в базе данных Merge Replication безумно медленны

У меня есть SQL-сервер, который настроен с репликацией слиянием на 800 мобильных клиентов, работающих под управлением SQL CE.

У сервера достаточно ресурсов, а строки внутри и вне компании более чем достаточны, репликация между клиентами и сервером в целом хороша, но мы получаем прерывистую ошибку, которую я просто не могу отследить.

Вчера нам нужно было вставить 550 записей в одну из наших основных таблиц, единственными триггерами, которые существуют, являются стандартные репликации слияния.

Эта вставка заняла 14 часов из-за того, что она постоянно зашла в тупик с помощью мобильных устройств, пытающихся синхронизировать.

Есть ли у кого-нибудь советы о том, как мы можем избежать блокировок на вставках и как ускорить весь процесс?

------ Обновление -----

Следуя некоторым комментариям, я запустил профайлер над одной вставкой, и я вижу много таких вещей

insert into dbo.MSmerge_current_partition_mappings with (rowlock) (publication_number, tablenick, rowguid, partition_id)
            select distinct 1, mc.tablenick, mc.rowguid, v.partition_id
            from dbo.MSmerge_contents mc with (rowlock) 
            JOIN dbo.[MSmerge_JEMProjectME_PromotionResource_PARTITION_VIEW] v with (rowlock) 
            ON mc.tablenick = 286358001
            and mc.rowguid = v.[rowguid]
            and mc.marker = @child_marker 
            and v.partition_id in (select partition_id from dbo.MSmerge_current_partition_mappings cpm with (rowlock) JOIN
                dbo.MSmerge_contents mc2 with (rowlock)
                ON cpm.rowguid = mc2.rowguid
                and mc2.marker = @marker)
            where not exists (select * from MSmerge_current_partition_mappings with (readcommitted, rowlock, readpast) where 
                publication_number = 1 and 
                tablenick = 286358001 and
                rowguid = v.[rowguid] and
                partition_id = v.partition_id)

Для многих таблиц, которые я не собираюсь вставлять... может ли это быть ключом?

Ответ 1

В конце индексы только помогли до сих пор, похоже, что репликация слияния не очень хорошо настроена в этой системе.

Однако использование Bulk Insert без запуска триггеров, а затем использование sp_addtabletocontents разрешило нашу проблему.

В качестве дополнительной заметки нам нужно было сделать базовое обновление

Обновить таблицу таблицы Column1 = Column1

после того, как мы сделали объемную вставку, чтобы репликация слияния уведомила другие связанные таблицы, которые она изменила, а не все данные распространяются правильно.

Ответ 2

мы недавно испытали такое же поведение в нашей системе, которое довольно похоже на ваше. Причиной было огромное количество данных в msmerge_contents и msmsmerge_current_partition_mappings, и мы заметили, что это может быть недостающий индекс, если посмотреть на количество строк, прочитанных в SQL Profiler. (49 000 000 прочтений для простой вставки в одном для таблиц показалось немного)

Решено 30 минут назад, добавив два индекса:

CREATE NONCLUSTERED INDEX [IX_MSmerge_current_partition_mappings_PERF1] ON [dbo].[MSmerge_current_partition_mappings] 
(
    [partition_id] ASC
)
INCLUDE ( [rowguid]) 


CREATE NONCLUSTERED INDEX [IX_msmerge_contents_PERF1] ON [dbo].[MSmerge_contents] 
(
    [marker] ASC
)
INCLUDE ( [rowguid])

Надеюсь, это поможет вам, это помогло нам сократить время запроса от 5 минут до 10 секунд.

- Через пару часов...

Мой коллега нашел еще один индекс, который еще больше увеличил производительность еще на 75%:

CREATE NONCLUSTERED INDEX [IX_MSmerge_current_partition_mappings_PERF2] ON [dbo].[MSmerge_current_partition_mappings] 
(
    [rowguid] ASC,
    [partition_id] ASC
)

Идентифицировать отсутствующий индекс Вы можете использовать следующий script для определения отсутствующих индексов, отсортированных с тем, который, как ожидается, увеличит производительность в верхней части (существует множество таких скриптов, которые были заимствованы из http://www.sherbaz.com/category/sqlserver/)

SELECT  sys.objects.name
, (avg_total_user_cost * avg_user_impact) * (user_seeks + user_scans) AS Impact
,  'CREATE NONCLUSTERED INDEX ix_IndexName ON ' + sys.objects.name COLLATE DATABASE_DEFAULT + ' ( ' + IsNull(mid.equality_columns, '') + CASE WHEN mid.inequality_columns IS NULL 
                THEN ''  
    ELSE CASE WHEN mid.equality_columns IS NULL 
                    THEN ''  
        ELSE ',' END + mid.inequality_columns END + ' ) ' + CASE WHEN mid.included_columns IS NULL 
                THEN ''  
    ELSE 'INCLUDE (' + mid.included_columns + ')' END + ';' AS CreateIndexStatement
, mid.equality_columns
, mid.inequality_columns
, mid.included_columns 
    FROM sys.dm_db_missing_index_group_stats AS migs 
            INNER JOIN sys.dm_db_missing_index_groups AS mig ON migs.group_handle = mig.index_group_handle 
            INNER JOIN sys.dm_db_missing_index_details AS mid ON mig.index_handle = mid.index_handle AND mid.database_id = DB_ID() 
            INNER JOIN sys.objects WITH (nolock) ON mid.OBJECT_ID = sys.objects.OBJECT_ID 
    WHERE     (migs.group_handle IN 
        ( 
        SELECT     TOP (500) group_handle 
            FROM          sys.dm_db_missing_index_group_stats WITH (nolock) 
            ORDER BY (avg_total_user_cost * avg_user_impact) * (user_seeks + user_scans) DESC))  
        AND OBJECTPROPERTY(sys.objects.OBJECT_ID, 'isusertable')=1 
    ORDER BY 2 DESC , 3 DESC