Различная производительность для простого запроса на обновление

#sql-server #tsql

#sql-server #tsql

Вопрос:

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

Используя следующий запрос (запутанный):

  CREATE TABLE #TmpTable (MapID int, Primary key(MapID))

 UPDATE MapTable
    SET Tstamp = GetDate() 
   FROM MapTable    
        JOIN Territory as Territory ON Territory.ID = MapTable.TerritoryID
        LEFT JOIN #TmpTable ON #TmpTable.MapID = MapTable.MapID  
  WHERE MapTable.TStamp > DateAdd(year, -100, GETDATE())    
    AND Territory.Name IS NOT null    
    AND Territory.Name NOT LIKE '!%'   
    AND #TmpTable.MapID IS NULL
  

Для 400k записей компьютер разработчика обновляется примерно 4 за секунды, но на тестовой машине он обновляется примерно 25 за секунды; одна и та же база данных была восстановлена на обеих машинах.

Проблема в том, что при запуске этого с помощью используемого нами инструмента время ожидания запросов устанавливается 30 равным секундам, и это время ожидания 90 % времени на тестовой машине.

Но план выполнения для обоих одинаков…

Может кто-нибудь подсказать, почему это так, и возможные оптимизации?

Комментарии:

1. Да, они могут иметь разную производительность на разных машинах, если это был ваш вопрос.

2. Если планы выполнения совпадают, возможно, это проблема ввода-вывода. SSD-диск по сравнению с сильно фрагментированным обычным диском?

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

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

5. Временная таблица заполняется во время before, оператор create используется только для отображения структуры. На самом деле, во время выполнения, когда мы обратили внимание на тайм-аут, временная таблица была пустой — в ней не было записи.

Ответ №1:

Единственное, что я вижу, что «может» повлиять на производительность, — это использование GETDATE() функции, которая может вызываться дважды для каждой записи, но обязательно один раз, так что это 400 тыс. вызовов функции!

Я бы поместил результат GETDATE() в переменную и использовал это, я всегда делаю это, если нет очень веской причины «нет», например, изменения даты во всем запросе требуются, как при пакетной обработке внутри a CURSOR .

Однако я сомневаюсь, что это будет основной проблемой с производительностью. При такой большой разнице во времени выполнения между разными машинами, где план выполнения одинаков, я бы рассматривал факторы, внешние по отношению к SQL, такие как загрузка ЦП, использование жесткого диска, скорость и фрагментация и т.д.

Комментарии:

1. Также устаревшая статистика, индексы, которые необходимо перестроить, и потенциальная блокировка. Или необходимость увеличения журнала во время обновления на тестовой машине. Есть целые книги, написанные о том, что может вызвать проблемы с производительностью, иногда это запрос, иногда это машинная среда, а иногда это newtork. Лично тестировщик должен запускать это на сервере среды контроля качества, который аналогичен производственному серверу, а не на его личном локальном сервере. Производительность на локальном сервере не имеет никакого отношения к тому, как он будет работать в реальной ситуации с сервером / сетью.

2. Ref GETDATE() — это константа времени выполнения. Это означает, что вызывается только один раз для каждого оператора. Поведение отличается, если вы включаете GETDATE() в скалярную функцию UDF. Попробуйте select *, getdate() gdt из bigtable