Низкая производительность SQL Server после выделения большего количества ЦП и ОЗУ

33

У нас есть SQL Server 2008 R2 (10.50.1600), работающий на виртуальном сервере Windows 2008 R2. После обновления ЦП с 1 ядра до 4 и ОЗУ с 4 ГБ до 10 ГБ мы заметили, что производительность хуже.

Некоторые наблюдения я вижу:

  1. Запрос, выполнение которого заняло <5 секунд, теперь занимает> 200 секунд.
  2. ЦП привязан на 100 с sqlservr.exe в качестве виновника.
  3. Выбор счетчика (*) для таблицы с 4,6 миллионами строк занял более 90 секунд.
  4. Процессы, запущенные на сервере, не изменились. Единственным изменением было увеличение процессора и оперативной памяти.
  5. Другие sql-серверы имеют статический файл подкачки, где этот сервер настроен для самостоятельного управления им.

Кто-нибудь сталкивался с этим вопросом раньше?

За sp_BlitzErik я побежал

EXEC dbo.sp_BlitzFirst @SinceStartup = 1;

Дайте мне эти результаты.

ждать статистику

Джефф
источник
9
В прошлый раз я видел похожий вопрос о SE, потому что кто-то включил ЦП и ОЗУ виртуальной машины, но на хосте ВМ не было столько ЦП и столько ОЗУ . Поэтому я бы сначала проверил это.
user253751

Ответы:

55

Здесь много чего происходит, и большая часть его довольно широкая и расплывчатая.

  1. 2008R2 RTM вышел 21 апреля 2010 года. Он полностью вне поддержки. Вы захотите установить приоритет для последнего пакета обновления, который появился всего 3 года назад. Таким образом, вы будете защищены, если столкнетесь со странной ошибкой или чем-то еще. Идите сюда, чтобы выяснить, что вам нужно скачать.

  2. Поскольку вы добавили vCPU (от 1 до 4) и не изменили никаких настроек, ваши запросы теперь могут идти параллельно. Я знаю, это звучит так, как будто они все будут быстрее, но держись!

  3. Возможно, вы добавили ОЗУ, но, возможно, вы не изменили Макс. Объем памяти сервера, чтобы ваш сервер мог этим воспользоваться.

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

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

Это покажет вам, что ваш сервер ждал с момента запуска.

EXEC dbo.sp_BlitzFirst @SinceStartup = 1;

Это покажет вам, какие запросы ожидают сейчас, в течение 30-секундного окна.

EXEC dbo.sp_BlitzFirst @Seconds = 30, @ExpertMode = 1;

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

Если вы видите, что они ждут CXPACKET, это означает, что ваши запросы идут параллельно и, возможно, растоптаны друг над другом. Если вы нажмете это, вы, вероятно, захотите увеличить порог стоимости для параллелизма до 50 и, возможно, понизить MAXDOP до 2.

После этого шага вы захотите использовать что-то вроде sp_WhoIsActive или sp_BlitzWho (последний находится в репозитории GitHub ранее), чтобы начать захват планов запросов. Помимо статистики ожидания, это одна из самых важных вещей, на которые вы можете посмотреть, чтобы выяснить, что происходит не так.

Возможно, вы также захотите проверить эту статью Джонатана Кехайаса о счетчиках VMWare, чтобы ознакомиться с SQL Server.

Обновить

Просмотр статистики ожидания и мальчик, они странные. Там определенно что-то не так с процессорами. Ваш сервер в основном сидит скучно, но когда все нагревается, все становится плохо. Я постараюсь сломать это легко.

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

  2. Вы действительно долго средние ожидания на SOS_SCHEDULER_YIELDи CXPACKET. Вы работаете на виртуальной машине, поэтому вам нужно убедиться, что у SQL Server есть резервирование или что ящик не переполнен. Шумный сосед может действительно испортить вам день здесь. Вы также захотите убедиться, что сервер / гостевая виртуальная машина / хост виртуальной машины не работают в режиме сбалансированной мощности. Это заставляет ваши процессоры вращаться до ненужных низких скоростей, и они не сразу возвращаются к полной скорости.

  3. Как они связаны? С 4 процессорами у вас есть 512 рабочих потоков. Имейте в виду, у вас было одинаковое количество с одним процессором, но теперь, когда ваши запросы могут идти параллельно, они могут потреблять гораздо больше рабочих потоков. В вашем случае 4 потока на параллельную ветвь параллельного запроса.

Что происходит параллельно? Скорее всего все. Пороговое значение стоимости по умолчанию для параллелизма равно 5. Это число было установлено по умолчанию в конце 90-х, работая на рабочем столе, который выглядел следующим образом .

NUTS

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

Когда запускается множество параллельных запросов, у вас заканчиваются эти рабочие потоки. Когда это происходит, запросы просто сидят и ждут начала потоков. Это также то, что SOS_SCHEDULER_YIELDприходит. Запросы отключают процессоры и не возвращаются в течение длительного времени. Я не вижу каких-либо ожидающих блокировок, поэтому вы, скорее всего, просто забиты ожиданиями параллелизма внутри запросов.

Что ты можешь сделать?

  1. Убедитесь, что в режиме сбалансированной мощности ничего нет
  2. Измените MAXDOP на 2
  3. Изменить порог стоимости для параллелизма на 50
  4. Следуйте статье Jon K. выше, чтобы проверить работоспособность VM
  5. Используйте вызываемый скрипт sp_BlitzIndexдля поиска любых отсутствующих запросов индекса.

Для более тщательного устранения неполадок ознакомьтесь с техническим документом, который я написал для Google, по настройке аппаратного обеспечения в облаке.

Надеюсь это поможет!

Эрик Дарлинг
источник
8

Да! Я сталкивался с такой ситуацией на SQL Server vms в нашей ферме серверов. Посмотрите на время готовности CPU хоста vm и счетчики драйвера всплывающей памяти. CPU READY TIME - БЛОГ ЧАСТЬ I и Понимание шаров VMware Работа с моим системным администратором была ключевой, но не простой ...

thundercougarfalcon
источник
5

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

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

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

В VMware ESXi вы можете увидеть это на продвинутых графиках через CPU Ready.

Вот одна из многих статей с реальным примером того, как это происходит и как это было диагностировано .

Добавление ОЗУ также может привести к внезапному падению производительности, если выделение ОЗУ виртуальной машины больше, чем у узла NUMA.

Кроме того, конфигурация ваших виртуальных ЦП (vSockets и vCores) может фактически влиять на некоторые приложения, такие как SQL-сервер. Это связано с тем, что SQL-сервер сам по себе поддерживает NUMA (чтобы избежать такого же падения производительности, связанного с NUMA) и потому что VMware может представлять виртуальные узлы NUMA по-разному.

Об этом говорится в сообщении в блоге на собственном сайте VMware .


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

briantist
источник
3

Просто небольшая помощь (не могу опубликовать это как комментарий), продолжая ответ @ sp_BlitzErik, я получил несколько запросов с Пиналом и Максом Верноном (не помню где), которые говорят, сколько MAXDOP вы должны использовать:

/*************************************************************************
Author          :   Kin Shah
Purpose         :   Recommend MaxDop settings for the server instance
Tested RDBMS    :   SQL Server 2008R2

**************************************************************************/
declare @hyperthreadingRatio bit
declare @logicalCPUs int
declare @HTEnabled int
declare @physicalCPU int
declare @SOCKET int
declare @logicalCPUPerNuma int
declare @NoOfNUMA int

select @logicalCPUs = cpu_count -- [Logical CPU Count]
    ,@hyperthreadingRatio = hyperthread_ratio --  [Hyperthread Ratio]
    ,@physicalCPU = cpu_count / hyperthread_ratio -- [Physical CPU Count]
    ,@HTEnabled = case 
        when cpu_count > hyperthread_ratio
            then 1
        else 0
        end -- HTEnabled
from sys.dm_os_sys_info
option (recompile);

select @logicalCPUPerNuma = COUNT(parent_node_id) -- [NumberOfLogicalProcessorsPerNuma]
from sys.dm_os_schedulers
where [status] = 'VISIBLE ONLINE'
    and parent_node_id < 64
group by parent_node_id
option (recompile);

select @NoOfNUMA = count(distinct parent_node_id)
from sys.dm_os_schedulers -- find NO OF NUMA Nodes 
where [status] = 'VISIBLE ONLINE'
    and parent_node_id < 64

-- Report the recommendations ....
select
    --- 8 or less processors and NO HT enabled
    case 
        when @logicalCPUs < 8
            and @HTEnabled = 0
            then 'MAXDOP setting should be : ' + CAST(@logicalCPUs as varchar(3))
                --- 8 or more processors and NO HT enabled
        when @logicalCPUs >= 8
            and @HTEnabled = 0
            then 'MAXDOP setting should be : 8'
                --- 8 or more processors and HT enabled and NO NUMA
        when @logicalCPUs >= 8
            and @HTEnabled = 1
            and @NoofNUMA = 1
            then 'MaxDop setting should be : ' + CAST(@logicalCPUPerNuma / @physicalCPU as varchar(3))
                --- 8 or more processors and HT enabled and NUMA
        when @logicalCPUs >= 8
            and @HTEnabled = 1
            and @NoofNUMA > 1
            then 'MaxDop setting should be : ' + CAST(@logicalCPUPerNuma / @physicalCPU as varchar(3))
        else ''
        end as Recommendations

-------------------------------------------------- -------

--MAX VERNON 

/* 
   This will recommend a MAXDOP setting appropriate for your machine's NUMA memory
   configuration.  You will need to evaluate this setting in a non-production 
   environment before moving it to production.

   MAXDOP can be configured using:  
   EXEC sp_configure 'max degree of parallelism',X;
   RECONFIGURE

   If this instance is hosting a Sharepoint database, you MUST specify MAXDOP=1 
   (URL wrapped for readability)
   http://blogs.msdn.com/b/rcormier/archive/2012/10/25/
   you-shall-configure-your-maxdop-when-using-sharepoint-2013.aspx

   Biztalk (all versions, including 2010): 
   MAXDOP = 1 is only required on the BizTalk Message Box
   database server(s), and must not be changed; all other servers hosting other 
   BizTalk Server databases may return this value to 0 if set.
   http://support.microsoft.com/kb/899000
*/
SET NOCOUNT ON;

DECLARE @CoreCount int;
SET @CoreCount = 0;
DECLARE @NumaNodes int;

/*  see if xp_cmdshell is enabled, so we can try to use 
    PowerShell to determine the real core count
*/
DECLARE @T TABLE (
    name varchar(255)
    , minimum int
    , maximum int
    , config_value int
    , run_value int
);
INSERT INTO @T 
EXEC sp_configure 'xp_cmdshell';
DECLARE @cmdshellEnabled BIT;
SET @cmdshellEnabled = 0;
SELECT @cmdshellEnabled = 1 
FROM @T
WHERE run_value = 1;
IF @cmdshellEnabled = 1
BEGIN
    CREATE TABLE #cmdshell
    (
        txt VARCHAR(255)
    );
    INSERT INTO #cmdshell (txt)
    EXEC xp_cmdshell 'powershell -OutputFormat Text -NoLogo -Command "& {Get-WmiObject -namespace "root\CIMV2" -class Win32_Processor -Property NumberOfCores} | select NumberOfCores"';
    SELECT @CoreCount = CONVERT(INT, LTRIM(RTRIM(txt)))
    FROM #cmdshell
    WHERE ISNUMERIC(LTRIM(RTRIM(txt)))=1;
    DROP TABLE #cmdshell;
END
IF @CoreCount = 0 
BEGIN
    /* 
        Could not use PowerShell to get the corecount, use SQL Server's 
        unreliable number.  For machines with hyperthreading enabled
        this number is (typically) twice the physical core count.
    */
    SET @CoreCount = (SELECT i.cpu_count from sys.dm_os_sys_info i); 
END

SET @NumaNodes = (
    SELECT MAX(c.memory_node_id) + 1 
    FROM sys.dm_os_memory_clerks c 
    WHERE memory_node_id < 64
    );

DECLARE @MaxDOP int;

/* 3/4 of Total Cores in Machine */
SET @MaxDOP = @CoreCount * 0.75; 

/* if @MaxDOP is greater than the per NUMA node
    Core Count, set @MaxDOP = per NUMA node core count
*/
IF @MaxDOP > (@CoreCount / @NumaNodes) 
    SET @MaxDOP = (@CoreCount / @NumaNodes) * 0.75;

/*
    Reduce @MaxDOP to an even number 
*/
SET @MaxDOP = @MaxDOP - (@MaxDOP % 2);

/* Cap MAXDOP at 8, according to Microsoft */
IF @MaxDOP > 8 SET @MaxDOP = 8;

PRINT 'Suggested MAXDOP = ' + CAST(@MaxDOP as varchar(max));
Racer SQL
источник
Первый скрипт возвращает пустой результат. Вторая возвращает предложенный MAXDOP = 2вариант, который соответствует @sp_BlitzErik. Благодарность!
Джефф