Обновление и вставка запросов Создание тупика

Я постараюсь объяснить свою проблему как можно более подробно, и я буду признателен за любую помощь / предложение. Моя проблема рассматривает тупик, вызванный двумя запросами (одна вставка и одно обновление). Я использую MS-SQL Server 2008

У меня есть два приложения, используя одну и ту же базу данных:

  1. веб-приложение (на каждом запросе несколько записей вставлены в таблицу впечатлений, вызывая сохраненную процедуру)
  2. служба Windows ( Вычисляет все впечатления, сделанные за одну минуту, каждую минуту, за предыдущую минуту и ​​устанавливают флаг на каждом из впечатлений, рассчитанных с помощью хранимой процедуры)

, веб-приложение вставляет записи отображения, не используя транзакцию, в то время как Приложение Windows Service вычисляет впечатления при использовании isolationLevel.readuncommed транзакции. Сохраненная процедура в приложении Windows Service делает что-то подобное:

Сервис Windows сохранена процедура:

Курортные петли все впечатления, которые имеют флаг ISCAlculated , установленный на false и date ISCALCULL flag to true на впечатлениях, которые имеют дату

DECLARE @nowTime datetime = convert(datetime, @now, 21) 
DECLARE dailyCursor CURSOR FOR

SELECT  Daily.dailyId, 
        Daily.spentDaily, 
        Daily.impressionsCountCache ,
        SUM(Impressions.amountCharged) as sumCharged, 
        COUNT(Impressions.impressionId) as countImpressions
FROM    Daily INNER JOIN Impressions on Impressions.dailyId = Daily.dailyId
WHERE   Impressions.isCharged=0 AND Impressions.showTime < @nowTime AND Daily.isActive = 1
GROUP BY Daily.dailyId, Daily.spentDaily, Daily.impressionsCountCache

OPEN dailyCursor

DECLARE @dailyId int, 
        @spentDaily decimal(18,6), 
        @impressionsCountCache int, 
        @sumCharged decimal(18,6), 
        @countImpressions int

FETCH NEXT FROM dailyCursor INTO @dailyId,@spentDaily, @impressionsCountCache, @sumCharged, @countImpressions

WHILE @@FETCH_STATUS = 0
    BEGIN   

        UPDATE Daily 
        SET spentDaily= @spentDaily + @sumCharged, 
            impressionsCountCache = @impressionsCountCache + @countImpressions
        WHERE dailyId = @dailyId

        FETCH NEXT FROM dailyCursor INTO @dailyId,@spentDaily, @impressionsCountCache, @sumCharged, @countImpressions
    END
CLOSE dailyCursor
DEALLOCATE dailyCursor

UPDATE Impressions 
SET isCharged=1 
WHERE showTime < @nowTime AND isCharged=0

Веб-приложение, сохраненная процедура:

Эта процедура довольно проста, она просто вставила запись в таблицу Отказ Вот укороченный фрагмент кода:

INSERT INTO Impressions 
(dailyId, date, pageUrl,isCalculated) VALUES 
(@dailyId, @date, @pageUrl, 0)

Код

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

//i send the date like this
string date = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff", 
CultureInfo.InvariantCulture);

SqlCommand comm = sql.StoredProcedureCommand("storedProcName", 
parameters, values);

, я очень часто испытываю тупики ( Исключения возникают в веб-приложении, а не на службе Windows), а после использования SQL-профилировщика я обнаружил, что тупики, вероятно, происходят из-за этих двух запросов (у меня нет большого опыта в анализе данных профилирования).

Последние данные трассировки, собранные из профилировщика SQL Server Server, можно найти внизу этого вопроса

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

Редактировать:

Вот код выполняется в приложении Windows Service:

SQL sql = new SQL();
DateTime endTime = DateTime.Now;
//our custom DAL class that opens a connection
sql.StartTransaction(IsolationLevel.ReadUncommitted);
try
{
    List properties = new List() { "now" };
    List values = new List() { endTime.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture) };
    SqlCommand comm = sql.StoredProcedureCommannd("ChargeImpressions", properties, values);
    comm.Transaction = sql.Transaction;
    ok = sql.CheckExecute(comm);
}
catch (Exception up)
{
    ok = false;
    throw up;
}
finally
{
    if (ok)
      sql.CommitTransaction();
    else
      sql.RollbackTransactions();
    CloseConn();
}

Редактирование:

Я добавил индексы на обоих таблицах, как предложено Martin Smith, как это:

CREATE NONCLUSTERED INDEX [IDX_Daily_DailyId] ON [dbo].[Daily] 
(
    [daily] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

и

CREATE NONCLUSTERED INDEX [IDX_Impressions_isCharged_showTime] ON [dbo].[Impressions] 
(
    [isCharged] ASC,
    [showTime] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

На данный момент нет исключений, сообщите позже

редактирование:

К сожалению, это не решило проблему тупика. Я начну след тупика в Profiler, чтобы посмотреть, будут ли тупики такими же, как раньше.

Отредактируйте:

вставил новый след (мне это выглядит так же, как и предыдущий), не смог бы захватить экран плана исполнения (слишком большой), но здесь - XML ​​из План выполнения . И вот скриншот плана исполнения вставки Query:

execution plan of the insert query

 
  
   
    
     
INSERT INTO Impressions 
    (dailyId, languageId, showTime, pageUrl, amountCharged, age, ipAddress, userAgent, portalId, isCharged,isCalculated) VALUES 
    (@dailyId, @languageId, @showTime, @pageUrl, @amountCharged, @age, @ip, @userAgent, @portalId, 0, 0)     
    
    
Proc [Database Id = 6 Object Id = 1362103893]    
   
   
    
     
UPDATE Impressions 
    SET isCharged=1 
    WHERE showTime &lt; @nowTime AND isCharged=0

    
    
    
Proc [Database Id = 6 Object Id = 1330103779]    
   
  
  
   
    
     
    
    
     
    
   
   
    
     
    
    
     
    
   
  
 

Редактировать:

После предложений от Джонатана Дикинсона:

  1. Я изменил хранимую процедуру (удаляет курсор),
  2. Я изменил idx_impressions_ischarged_showtime, чтобы не разрешить страницу_locks и
  3. , добавил -1 второе на свойство @Now в приложении службы Windows, чтобы избежать пограничных случаев тупиков.

Обновление:

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

Надеюсь, последнее обновление:

Изменения, предложенные Мартином Смитом, теперь в прямом эфире, вставьте запрос вставки теперь использует не кластерный индекс и теоретически это должно исправить проблему. На данный момент никаких исключений не сообщалось (удерживая мои пальцы скрещенными)

13
задан 12 revs 7 September 2011 в 10:15
поделиться