Обмен таблицами ms-sql - PullRequest
18 голосов
/ 03 марта 2009

Я хочу поменять таблицы наилучшим образом.
У меня есть таблица IpToCountry, и я создаю новую каждую неделю в соответствии с внешним CSV-файлом, который я импортирую.

Самый быстрый способ, которым я нашел переключение, заключался в следующем:

sp_rename IpToCountry IpToCountryOld
go
sp_rename IpToCountryNew IpToCountry
go

Проблема в том, что к таблице все еще можно получить доступ в промежутке.
Как мне подойти к этой проблеме в SQL?
Рассматривается использование sp_getapplock и sp_releaseapplock, но я хочу, чтобы функция чтения из таблицы была максимально быстрой.

Ответы [ 6 ]

16 голосов
/ 03 марта 2009

Если вы не можете обновить / вставить в существующую таблицу, почему бы вам не обернуть весь доступ к таблице, используя представление ?

Например, вы могли бы изначально сохранить ваши данные в таблице с именем IpToCountry20090303 , и ваше представление будет выглядеть примерно так:

CREATE VIEW IpToCountry
AS
SELECT * FROM IpToCountry20090303

Когда поступают новые данные, вы можете создать и заполнить таблицу IpToCountry20090310 . Как только таблица заполнится, просто обновите ваше представление:

ALTER VIEW IpToCountry
AS
SELECT * FROM IpToCountry20090310

Переключатель будет полностью атомарным, без какой-либо явной блокировки или транзакций. После обновления представления вы можете просто удалить старую таблицу (или оставить ее, если хотите).

1 голос
/ 11 марта 2011

У меня были проблемы с настройкой функций секционирования. CREATE и DROP PARTITION являются блокирующими операциями, и у вас мало контроля над блокировкой, и, если она не может получить блокировку, она потерпит неудачу с уровнем серьезности 16 и разорвет ваше соединение - которое вы не можете перехватить и повторить без восстановления связь. Но это может работать просто отлично для вас. Кроме того, MSS Enterprise Edition требуется, вы не можете использовать SE - может быть слишком много для некоторых небольших или более дорогих магазинов.

Я также обнаружил, что представление redef блокирует в высоком масштабе (= объем транзакции + объем постоянно вставляемых данных, в моем случае) для таблиц и объектов sys, поэтому эти операции могут зайти в тупик при таких вещах, как переиндексация и DTCC - и в одном случае, особенно с пользователем в SSMS (из всех вещей), пытающимся просмотреть представления в обозревателе объектов (кто-то должен рассказать этим ребятам о READPAST). Опять же, ваш пробег может отличаться.

Напротив, sp_rename хорошо работает для меня в масштабе: он дает вам контроль над блокировкой и ее областью действия. Чтобы решить проблему блокировки до обмена, попробуйте, как показано ниже. На первый взгляд кажется, что при большой громкости такая же проблема с масштабом ... но я не видел ее на практике. Так что, работает для меня ... но опять же, потребности и опыт у всех разные.

DECLARE @dummylock bit 
BEGIN TRANSACTION 
BEGIN TRY
   -- necessary to obtain exclusive lock on the table prior to swapping
   SELECT @dummylock = 1 WHERE EXISTS (SELECT 1 FROM A WITH (TABLOCKX))
   -- may or may not be necessary in your case
   SELECT @dummylock = 1 WHERE EXISTS (SELECT 1 FROM B WITH (TABLOCKX))
   exec sp_rename 'A', 'TEMP'
   exec sp_rename 'B', 'A'
   exec sp_rename 'TEMP', 'B'
   COMMIT TRANSACTION
END TRY
BEGIN CATCH
   -- other error handling here if needed
   ROLLBACK TRANSACTION 
END CATCH
1 голос
/ 03 марта 2009

Другим способом реализации того, чего вы хотите добиться, было бы использование разбиения таблиц, метод, который доступен в Enterprise Edition SQL Server.

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

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

http://msdn.microsoft.com/en-us/library/ms345146.aspx

Ура, Джон

0 голосов
/ 13 апреля 2013

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

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

Хранимая процедура может создать новые таблицы или вернуть старые таблицы в зависимости от предоставленных параметров.

0 голосов
/ 03 марта 2009

Не можете ли вы выполнить импорт в одну таблицу в нерабочее время?

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

Какова структура импортируемых данных, дизайн таблицы, формат, PK и т. Д.? Исходя из этого, мы сможем дать вам лучший ответ.

0 голосов
/ 03 марта 2009

Что происходит с IpToCountryOld? Вы выбрасываете это? В таком случае, почему бы не обрезать IpToCountry и импортировать мои новые данные.

Если вам нужно сохранить данные, как насчет сохранения даты загрузки в таблице и сохранения «текущей» даты загрузки в месте, которое будет использоваться в предложении WHERE? Затем вы переключаете текущую дату, когда данные успешно загружены.

Вы не говорите, какую БД вы используете, поэтому я не знаю, насколько это полезно, но есть ли у вас хранимые процедуры, которые ссылаются на таблицу? Имейте в виду, что на некоторых платформах SP компилируются с использованием внутренних ссылок на таблицы, которые не изменяются при переименовании, поэтому существует риск, что SP не получат ваши новые данные без перекомпиляции. То же самое может быть верно для представлений и сохраненных проанализированных запросов.

...