2013-03-18 6 views
1

Я использую MS SQL Server 2008 У меня есть таблица, которая постоянно используется (данные всегда меняются и вставляются в нее) содержит ~ 70 строк в мельнице, Я пытаясь запустить простой запрос по таблице с хранимой процедурой, которая должна занять несколько дней,Выполнение больших запросов в backgroud MS SQL

Мне нужна таблица, чтобы оставаться в рабочем состоянии, теперь я выполнил хранимую процедуру и через какое-то время каждый простой выбор по запросу идентификации что я пытаюсь выполнить на столе, не реагирует/работает слишком много времени, чтобы его разбить

Что мне делать? вот как моя хранимая процедура выглядит следующим образом:

SET NOCOUNT ON; 
update SOMETABLE 
set 
[some_col] = dbo.ufn_SomeFunction(CONVERT(NVARCHAR(500), another_column)) 
WHERE 
[some_col] = 243 

даже если я попробовать его с этим на где п (с «и» логики ..):

ID_COL > 57000000 and ID_COL < 60000000 and 

это еще Безразлично» т работа

BTW- SomeFunction делает несколько простых действий mathmatics и смотрит строки в другой таблице, которая содержит около 300k элементов, но никогда не изменял

Я был бы рад ч ухо любой совет

+0

Какой уровень транзакции вы используете? Есть ли указатель на some_col? Какой индекс указан в ID_COL? – TToni

+0

id_col - это первичное тождество (растущее целое число) ... индексов нет. readcommit transaction level ... –

+4

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

ответ

3

С моей точки зрения у вашего сервера серьезная проблема с производительностью. Даже если предположить, что ни одна из записей в запросе

select some_col with (nolock) where id_col between 57000000 and 57001000 

был в памяти, это не должно занять 21 секунд, чтобы последовательно прочитать несколько страниц с диска (ваш кластерный индекс на id_col не должен быть фрагментирован, если это авто-идентификатор, и вы не делали что-то глупое, как добавление «desc» к определению индекса).

Но если вы не можете/не исправите это, моим советом будет сделать обновление в небольших пакетах, например 100-1000 записей (в зависимости от того, сколько времени функция поиска потребляет). Одно обновление/транзакция занимает не более 30 секунд.

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

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

Чтобы избежать взаимоблокировок, ваш оператор обновления должен блокировать все записи, которые он будет изменять сразу. Способ сделать это, чтобы поместить один оператор обновления (с только несколько строк, ограниченных id_col) в сериализуемой сделки как

IF @@TRANCOUNT > 0 
    -- Error: You are in a transaction context already 

SET NOCOUNT ON 
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE 

-- Insert Loop here to work "x" through the id range 
    BEGIN TRANSACTION 
    UPDATE SOMETABLE 
     SET [some_col] = dbo.ufn_SomeFunction(CONVERT(NVARCHAR(500), another_column)) 
     WHERE [some_col] = 243 AND id_col BETWEEN x AND x+500 -- or whatever keeps the update in the small timerange 
    COMMIT 
-- Next loop 

-- Get all new records while you where running the loop. If these are too many you may have to paginate this also: 
BEGIN TRANSACTION 
    UPDATE SOMETABLE 
    SET [some_col] = dbo.ufn_SomeFunction(CONVERT(NVARCHAR(500), another_column)) 
    WHERE [some_col] = 243 AND id_col >= x 
COMMIT 

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

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

+0

Прошу прощения, возможно, возникло недоразумение - запуск хранимой процедуры между 57000000 и 57001000 занял 21 секунду. Как вы можете видеть, выбор из 100 предметов занял 0 секунд ... в любом случае ваш ответ кажется разумным, и я дам ему попробуйте и отправьте ответ. спасибо за помощь! –

+0

Да, поэтому я ответил на запрос 1000 пунктов в ответе :-). Я думаю, что 21 секунда для выбора 1000 целых чисел через первичный ключ с кластеризованным индексом и (nolock) слишком велика. Из-за (nolock) 21 секунда не может исходить из другой блокирующей блокировки, и если вы разрешите ей запускаться непосредственно на сервере, это также не может быть проблемой сети. Это просто сырая производительность перехода на первую запись индекса и получение 1000 тс из следующих записей. На том, что я считаю нормальным сервером, который должен быть в пределах одной секунды, даже с довольно длинной очереди на диск. – TToni

+0

Во всяком случае, просто экспериментируйте с размером окна, чтобы получить разумное время для каждого обновления. – TToni

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