2013-02-28 4 views
0

Я предварить этот вопрос, говоря, мой SQL не очень хорошо :)Избегайте код в SQL

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

У нас есть много кода, который выглядит как:

IF @activeCache = 0 
    BEGIN WORK ON TABLE 1 AS IT IS INACTIVE 
ELSE 
    BEGIN WORK ON TABLE 0 AS IT IS INACTIVE 

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

Есть ли какие-либо конструкции sql, которые могут нам помочь? Мы бы предпочли не использовать динамический sql, если это возможно.

+0

[Связанный вопрос на сайте DBA] (http://dba.stackexchange.com/q/33470) –

ответ

2

Вы можете использовать CREATE SYNONYM, чтобы эффективно создать постоянный псевдоним (или «синоним», если хотите) для объекта. Вы можете запустить логику один раз решить, какие таблицы цели, а затем запустить:

CREATE SYNONYM WorkingTable FOR Table1 
CREATE SYNONYM MainTable FOR Table2 

Тогда для переключения:

DROP SYNONYM WorkingTable 
DROP SYNONYM MainTable 
CREATE SYNONYM WorkingTable FOR Table2 
CREATE SYNONYM MainTable FOR Table1 

И везде в ваших скриптах, вы можете просто ссылаться на WorkingTable обновлений, и MainTable для чтения.

Это, как говорится, я согласен с другими комментариями/ответами на вопрос, является ли это лучшим способом работы.

1

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

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

begin try 
begin tran 
delete * from MainTable with (tablockx) 
insert MainTable 
select * from StagingTable with (tablockx) 
commit 

end try 
begin catch 
rollback 
raiserror('An error occurred swapping staging data', 16,16) 
end catch 

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

В зависимости от данных, которые вы можете сделать добавочное обновление главной таблицы:

-- delete rows which no longer exist 
delete MainTable 
from MainTable 
where not exists (select 1 from StagingTable where StagingTable.primaryKey = MainTable.primaryKey) 

-- Insert new rows 
insert MainTable 
select * 
from StagingTable 
where not exists (select 1 from MainTable where StagingTable.primaryKey = MainTable.primaryKey) 


-- update rows which have changed 
update MainTable 
set 
    col1 = stagingTable.col1, 
    col2 = stagingTable.col2 
from MainTable inner join StagingTable on StagingTable.primaryKey = MainTable.primaryKey 
where 1=2 
    -- Need to compare every column, only update if one is different 
    -- Both null counts as the same - compare nullity 
    OR case when MainTable.col1 is null then 0 else 1 end <> case when StagingTable.col1 is null then 0 else 1 end 
    OR MainTable.col1 <> StagingTable.col1 
    OR case when MainTable.col2 is null then 0 else 1 end <> case when StagingTable.col2 is null then 0 else 1 end 
    OR MainTable.col2 <> StagingTable.col2 
+0

+1 Для избежания идеи 2-х столов. Измельчение и переход от стола к столу звучат как плохие новости для меня ... Что делать, если что-то не получается на полпути через ваш код? Если вам нужны две таблицы с одинаковыми данными, вы должны использовать репликацию, балансировку нагрузки на нескольких серверах или что-то в этом роде. – twoleggedhorse

+0

Спасибо, единственная проблема, с которой я вижу, - это займет много времени, чтобы переключиться, поскольку мы опорожняем основную таблицу и заселяем ее, что означает, что она будет уменьшаться в течение своей продолжительности, которая побеждает цель «двойного буферирования» – moosecode

+0

@moosecode Во-первых, вы приурочили его? Это НАСТОЯТЕЛЬНО проблема, или это просто теория?Использование 'TABLOCKX' ускорит его. Также вы изучали нелегальные операции, которые также должны быть быстрее? Во-вторых, будет ли второй вариант работать? Другие пользователи могут видеть частично обновленные данные. Это может быть или не быть проблемой в зависимости от данных и того, что они делают с этим. – Ben

1

Вы можете создать Инлайн табличного функцию, которая принимает @activeCache в качестве параметра. Выберите все данные из соответствующей таблицы в соответствии с параметром в этой функции. Я не уверен в производительности.

Смежные вопросы