Както всеки ветеран в производството DBA знае, често сте подложен на значителен натиск да диагностицирате и облекчите проблемите с производителността на базата данни възможно най-бързо. Ето три неща, от които може да можете да се възползвате, в зависимост от вашето работно натоварване и инфраструктура, за да окажат много забележимо положително въздействие върху производителността на вашата база данни.
Настройка на индекса на основния магазин на редове
Повечето екземпляри на SQL Server, които съм срещал в кариерата си, са имали някои сравнително лесни възможности за настройка на индекса за съхранение на редове. Едно хубаво нещо при настройката на индекса на магазина на редове е, че тя е по-често под ваш директен контрол като DBA, особено в сравнение с настройката на заявки или съхранени процедури, които често са под контрола на разработчици или доставчици на три страни.
Някои администратори на база данни не са склонни да правят каквато и да е настройка на индекса (особено на бази данни от 3 страни), защото се притесняват да не счупят нещо или да застрашат поддръжката на доставчика за базата данни или приложението. Очевидно трябва да бъдете по-внимателни с базите данни на 3 страни и да се опитате да се свържете с доставчика, преди сами да направите каквито и да е промени в индекса, но в някои ситуации може да нямате друга жизнеспособна алтернатива (освен да решите проблема с по-бърз хардуер и съхранение ).
Можете да изпълните няколко ключови заявки от моите заявки за диагностична информация на SQL Server, за да получите добра представа, ако може да имате някои лесни възможности за настройка на индекса на вашия екземпляр или база данни. Трябва да внимавате за липсващи заявки за индекс, предупреждения за липсващи индекси, недостатъчно използвани или неизползвани неклъстерни индекси и възможни възможности за компресиране на данни.
Необходими са известен опит, добра преценка и познания за вашето работно натоварване, за да направите правилна настройка на индекса. Твърде обичайно е да видите как хората правят неправилна настройка на индекса, като прибързано правят много промени в индекса, без да направят правилния анализ.
Ето някои заявки, които обичам да използвам на ниво база данни:
-- Missing Indexes for current database by Index Advantage (Query 1) (Missing Indexes) SELECT DISTINCT CONVERT(decimal(18,2), user_seeks * avg_total_user_cost * (avg_user_impact * 0.01)) AS [index_advantage], migs.last_user_seek, mid.[statement] AS [Database.Schema.Table], mid.equality_columns, mid.inequality_columns, mid.included_columns, migs.unique_compiles, migs.user_seeks, migs.avg_total_user_cost, migs.avg_user_impact, OBJECT_NAME(mid.[object_id]) AS [Table Name], p.rows AS [Table Rows] FROM sys.dm_db_missing_index_group_stats AS migs WITH (NOLOCK) INNER JOIN sys.dm_db_missing_index_groups AS mig WITH (NOLOCK) ON migs.group_handle = mig.index_group_handle INNER JOIN sys.dm_db_missing_index_details AS mid WITH (NOLOCK) ON mig.index_handle = mid.index_handle INNER JOIN sys.partitions AS p WITH (NOLOCK) ON p.[object_id] = mid.[object_id] WHERE mid.database_id = DB_ID() AND p.index_id < 2 ORDER BY index_advantage DESC OPTION (RECOMPILE); ------ -- Look at index advantage, last user seek time, number of user seeks to help determine source and importance -- SQL Server is overly eager to add included columns, so beware -- Do not just blindly add indexes that show up from this query!!! -- Find missing index warnings for cached plans in the current database (Query 2) (Missing Index Warnings) -- Note: This query could take some time on a busy instance SELECT TOP(25) OBJECT_NAME(objectid) AS [ObjectName], cp.objtype, cp.usecounts, cp.size_in_bytes, query_plan FROM sys.dm_exec_cached_plans AS cp WITH (NOLOCK) CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) AS qp WHERE CAST(query_plan AS NVARCHAR(MAX)) LIKE N'%MissingIndex%' AND dbid = DB_ID() ORDER BY cp.usecounts DESC OPTION (RECOMPILE); ------ -- Helps you connect missing indexes to specific stored procedures or queries -- This can help you decide whether to add them or not -- Possible Bad NC Indexes (writes >= reads) (Query 3) (Bad NC Indexes) SELECT OBJECT_NAME(s.[object_id]) AS [Table Name], i.name AS [Index Name], i.index_id, i.is_disabled, i.is_hypothetical, i.has_filter, i.fill_factor, s.user_updates AS [Total Writes], s.user_seeks + s.user_scans + s.user_lookups AS [Total Reads], s.user_updates - (s.user_seeks + s.user_scans + s.user_lookups) AS [Difference] FROM sys.dm_db_index_usage_stats AS s WITH (NOLOCK) INNER JOIN sys.indexes AS i WITH (NOLOCK) ON s.[object_id] = i.[object_id] AND i.index_id = s.index_id WHERE OBJECTPROPERTY(s.[object_id],'IsUserTable') = 1 AND s.database_id = DB_ID() AND s.user_updates > (s.user_seeks + s.user_scans + s.user_lookups) AND i.index_id > 1 AND i.[type_desc] = N'NONCLUSTERED' AND i.is_primary_key = 0 AND i.is_unique_constraint = 0 AND i.is_unique = 0 ORDER BY [Difference] DESC, [Total Writes] DESC, [Total Reads] ASC OPTION (RECOMPILE); ------ -- Look for indexes with high numbers of writes and zero or very low numbers of reads -- Consider your complete workload, and how long your instance has been running -- Investigate further before dropping an index! -- Breaks down buffers used by current database by object (table, index) in the buffer cache (Query 4) (Buffer Usage) -- Note: This query could take some time on a busy instance SELECT OBJECT_NAME(p.[object_id]) AS [Object Name], p.index_id, CAST(COUNT(*)/128.0 AS DECIMAL(10, 2)) AS [Buffer size(MB)], COUNT(*) AS [BufferCount], p.[Rows] AS [Row Count], p.data_compression_desc AS [Compression Type] FROM sys.allocation_units AS a WITH (NOLOCK) INNER JOIN sys.dm_os_buffer_descriptors AS b WITH (NOLOCK) ON a.allocation_unit_id = b.allocation_unit_id INNER JOIN sys.partitions AS p WITH (NOLOCK) ON a.container_id = p.hobt_id WHERE b.database_id = CONVERT(int, DB_ID()) AND p.[object_id] > 100 AND OBJECT_NAME(p.[object_id]) NOT LIKE N'plan_%' AND OBJECT_NAME(p.[object_id]) NOT LIKE N'sys%' AND OBJECT_NAME(p.[object_id]) NOT LIKE N'xml_index_nodes%' GROUP BY p.[object_id], p.index_id, p.data_compression_desc, p.[Rows] ORDER BY [BufferCount] DESC OPTION (RECOMPILE); ------ -- Tells you what tables and indexes are using the most memory in the buffer cache -- It can help identify possible candidates for data compression
Използване на отложена издръжливост
Функцията за отложена издръжливост беше добавена към продукта в SQL Server 2014, така че е налична от доста време. Отложените трайни транзакции са асинхронни и отчитат транзакция като успешна преди регистрационните записи за транзакцията всъщност се записват в подсистемата за съхранение. Отложените трайни транзакции всъщност не стават трайни, докато записите в дневника на транзакциите не бъдат изтрити на диск.
Тази функция е налична във всички издания на SQL Server. Въпреки това рядко го виждам да се използва, когато разглеждам клиентски бази данни. Забавената издръжливост отваря възможността за загуба на някои данни, до цял буфер на журнала в най-лошия сценарий (както е обяснено от Пол Рандал тук), така че определено не е подходящо за сценарий на RPO, където абсолютно никаква загуба на данни не е приемлива.
Отложената издръжливост намалява латентността на транзакциите, тъй като не изчаква log IO да завърши и да върне контрола обратно на клиента, а също така намалява заключването и конкуренцията на диска за едновременни транзакции. Тези две предимства често могат да имат много положителен ефект върху вашата заявка и производителност на приложението с подходящото много тежко за писане натоварване.
Отложената издръжливост най-често ще помогне за тежки работни натоварвания от тип OLTP, които имат много чести, малки транзакции на запис, при които виждате висока латентност при запис на ниво файл от sys.dm_io_virtual_file_stats в регистрационния файл на транзакциите и/или виждате високо изчакване на WRITELOG от sys. dm_os_wait_stats.
Можете лесно да принудите SQL Server 2014 или по-нова версия да използва отложена издръжливост за всички транзакции (без промени в кода), като изпълните следната команда:
ALTER DATABASE AdventureWorks2014 SET DELAYED_DURABILITY = FORCED;
Имал съм клиенти, които програмно включват и изключват отложена издръжливост по различно време на деня (като по време на планирана ETL или дейност по поддръжка). Имал съм и клиенти, които използват отложена издръжливост по всяко време, тъй като имат подходящо работно натоварване и толерантност към риска от загуба на данни.
И накрая, имах клиенти, които никога не биха обмислили използването на отложена издръжливост или просто не се нуждаят от нея с работното си натоварване. Ако подозирате, че работното ви натоварване може се възползвате от използването на отложена издръжливост, но сте загрижени за възможната загуба на данни, тогава има други алтернативи, които можете да обмислите.
Една алтернатива е функцията за постоянен буфер на регистрационни файлове в SQL Server 2016 SP1, където можете да създадете втори, 20MB регистрационен файл на транзакциите в обем за съхранение в режим на директен достъп (DAX), който се хоства на устройство с постоянна памет NV-DIMM. Този допълнителен регистрационен файл на транзакциите се използва за кеширане на опашката на дневника с достъп на ниво байт, който заобикаля конвенционалния стек за съхранение на ниво блок.
Ако смятате, че работното ви натоварване може да се възползва от използването на функцията за постоянен буфер на регистрационни файлове, можете да експериментирате с временно използване на отложена издръжливост, за да видите дали има действителна полза от работата ви, преди да похарчите парите за постоянната памет на NV-DIMM, която сте ще трябва да използва функцията за постоянен буфер на журнала.
Преместване на tempdb към Intel Optane DC P4800X Storage
Имах голям успех с няколко скорошни клиенти, които преместиха своите tempdb файлове с база данни от друг тип хранилище на логическо устройство, което беше подкрепено от няколко Intel Optane DC P4800X PCIe NVMe карти за съхранение (в софтуерен RAID 1 масив).
Тези карти за съхранение се предлагат с капацитет от 375GB, 750GB и 1,5TB (въпреки че капацитетът от 1,5TB е чисто нов и все още е труден за намиране). Те имат изключително ниска латентност (много по-ниска от всеки тип NAND флаш памет), отлична производителност на произволен вход/изход при ниска дълбочина на опашката (много по-добра от NAND флаш памет), с постоянни времена за реакция при четене при много тежко натоварване при запис.
Те също така имат по-висока издръжливост на запис в сравнение с „интензивно записване“ корпоративно NAND флаш хранилище и тяхната производителност не се влошава, тъй като са близо до пълни. Тези характеристики правят тези карти изключително подходящи за много тежки натоварвания на tempdb, особено тежки OLTP натоварвания и ситуации, при които използвате RCSI във вашите потребителски бази данни (което поставя полученото работно натоварване на хранилището на версиите върху tempdb).
Също така е много често да видите висока латентност при запис на ниво файл на tempdb файлове с данни от sys.dm_io_virtual_file_stats DMV, така че преместването на вашите tempdb файлове с данни в хранилището на Optane е един от начините за директно решаване на този проблем, който може да е по-бърз и по-лесен от конвенционалните настройка на натоварването.
Друга възможна употреба на картите за съхранение на Optane е като дом за вашите регистрационни файлове. Можете също да използвате хранилището на Optane с наследени версии на SQL Server (стига вашата ОС и хардуер да го поддържат). Това е възможна алтернатива на използването на отложена издръжливост (което изисква SQL Server 2014) или използването на функцията за постоянен буфер на журнал (която изисква SQL Server 2016 SP1).
Заключение
Обсъдих три техники за постигане на бърза печалба със SQL Server:
- Конвенционалната настройка на индекса на магазина на редове е приложима за всички версии на SQL Server и е един от най-добрите инструменти във вашия арсенал.
- Отложената издръжливост е налична в SQL Server 2014 и по-нова версия и може да бъде много полезна при някои видове натоварване (и изисквания за RPO). Постоянният буфер на журнала е наличен в SQL Server 2016 SP1 и дава подобни предимства като забавената издръжливост, без опасност от загуба на данни.
- Преместването на определени типове файлове на база данни в хранилището на Intel Optane може да помогне за облекчаване на проблемите с производителността с tempdb или с регистрационни файлове за транзакции на потребителска база данни. Можете да използвате хранилището на Optane с наследени версии на SQL Server и не са необходими промени в кода или конфигурацията.