Вставки в базу данных репликации слиянием безумно медленные
У меня есть SQL server, который настроен с репликацией слиянием на 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)
для многих таблиц, которые я не должен быть вставка в... может, это ключ к разгадке?
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
)
определить отсутствующий индекс Вы можете использовать следующий скрипт для определения отсутствующих индексов, отсортированных с тем, который, как ожидается, увеличит производительность в верхней части (существует множество таких сценариев, которые были заимствованы из 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
в конце индексы только помогли до сих пор, похоже, репликация слиянием не очень хорошо настроена в этой системе.
однако использование Bulk Insert без запуска триггеров, а затем использование sp_addtabletocontents решило нашу проблему.
в качестве примечания мы должны были сделать базовое обновление
обновить набор таблиц Column1 = Column1
после того, как мы сделали массовую вставку, чтобы репликация слиянием уведомила другие связанные таблицы, что она изменила еще не все данные распространяются правильно.