Обмен таблицами ms-sql

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

Самый быстрый способ сделать это - сделать следующее:

sp_rename IpToCountry IpToCountryOld
go
sp_rename IpToCountryNew IpToCountry
go

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

6 ответов

Решение

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

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

CREATE VIEW IpToCountry
AS
SELECT * FROM IpToCountry20090303

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

ALTER VIEW IpToCountry
AS
SELECT * FROM IpToCountry20090310

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

У меня были проблемы с получением функций разбиения для работы в масштабе. 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

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

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

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

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

Ура, Джон

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

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

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

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

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

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

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

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

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

Другие вопросы по тегам