sql >> Databáze >  >> RDS >> Sqlserver

Tři výhry výkonu Easy SQL Server

Jak každý zkušený produkční DBA ví, často jste pod velkým tlakem, abyste co nejrychleji diagnostikovali a zmírnili problémy s výkonem databáze. Zde jsou tři věci, které můžete využít, v závislosti na vaší pracovní zátěži a infrastruktuře, a mít velmi znatelný pozitivní dopad na výkon vaší databáze.

Ladění indexu základního úložiště řádků

Většina instancí SQL Serveru, se kterými jsem se ve své kariéře setkal, měla poměrně snadné možnosti ladění indexu úložiště řádků. Jedna pěkná věc na ladění indexu úložiště řádků je, že je častěji pod vaší přímou kontrolou jako DBA, zvláště ve srovnání s laděním dotazů nebo uložených procedur, které jsou často pod kontrolou vývojářů nebo třístranných dodavatelů.

Někteří správci databází se zdráhají provádět jakékoli ladění indexu (zejména na databázích 3 stran), protože se obávají, že něco rozbijí nebo ohrozí podporu dodavatele pro databázi nebo aplikaci. Je zřejmé, že musíte být opatrnější u 3stranných databází a pokusit se oslovit dodavatele, než sami provedete jakékoli změny indexu, ale v některých situacích možná nemáte jinou schůdnou alternativu (kromě řešení problému rychlejším hardwarem a úložištěm). ).

Můžete spustit několik klíčových dotazů z mých SQL Server Diagnostic Information Queries, abyste získali dobrou představu, zda máte nějaké příležitosti pro snadné ladění indexu ve vaší instanci nebo databázi. Měli byste si dávat pozor na chybějící požadavky na index, chybějící varování o indexu, málo používané nebo nepoužívané indexy bez klastrů a možné příležitosti ke kompresi dat.

Správné ladění indexu vyžaduje určité zkušenosti, dobrý úsudek a znalost vaší pracovní zátěže. Je až příliš běžné, že lidé provádějí nesprávné ladění indexu tím, že unáhleně provádějí mnoho změn indexu, aniž by provedli náležitou analýzu.

Zde jsou některé dotazy, které rád používám na úrovni databáze:

-- 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

Použití zpožděné trvanlivosti

Funkce odložené trvanlivosti byla přidána do produktu v SQL Server 2014, takže je k dispozici již nějakou dobu. Odložené trvalé potvrzení transakce jsou asynchronní a hlásí potvrzení transakce jako úspěšné před záznamy protokolu pro transakci jsou ve skutečnosti zapsány do úložného subsystému. Zpožděné trvalé transakce se ve skutečnosti nestanou trvalými, dokud nejsou záznamy protokolu transakcí vyprázdněny na disk.

Tato funkce je dostupná ve všech edicích SQL Server. Navzdory tomu zřídka vidím, že se používá, když se podívám na databáze klientů. Zpožděná trvanlivost otevírá možnost určité ztráty dat, v nejhorším případě až celé vyrovnávací paměti protokolu (jak zde vysvětlil Paul Randal), takže rozhodně není vhodné pro scénář RPO, kde není přijatelná absolutně žádná ztráta dat.

Zpožděná trvanlivost snižuje latenci transakcí, protože nečeká na dokončení IO protokolu a vrácení řízení zpět klientovi, a také snižuje zamykání a spory o disk u souběžných transakcí. Tyto dvě výhody mohou mít často velmi pozitivní vliv na výkon vašeho dotazu a aplikace při vhodné pracovní zátěži, která je velmi náročná na zápis.

Zpožděná trvanlivost nejčastěji pomůže velkým pracovním zátěžím typu OLTP, které mají velmi časté, malé transakce zápisu, kde vidíte vysokou latenci zápisu na úrovni souboru ze sys.dm_io_virtual_file_stats v souboru protokolu transakcí a/nebo vidíte vysoké čekání WRITELOG od sys. dm_os_wait_stats.

SQL Server 2014 nebo novější můžete snadno vynutit, aby používal pro všechny transakce zpožděnou trvanlivost (beze změn kódu) spuštěním následujícího příkazu:

ALTER DATABASE AdventureWorks2014 SET DELAYED_DURABILITY = FORCED;

Měl jsem klienty, kteří programově zapínali a vypínali zpožděnou trvanlivost v různou denní dobu (například během plánované ETL nebo údržby). Měl jsem také klienty, kteří používají zpožděnou trvanlivost vždy, protože mají odpovídající pracovní zátěž a toleranci rizika ztráty dat.

Konečně jsem měl klienty, kteří by nikdy neuvažovali o použití opožděné trvanlivosti, nebo ji prostě nepotřebují při své pracovní zátěži. Pokud máte podezření, že vaše pracovní vytížení může těžit z použití opožděné trvanlivosti, ale máte obavy z možné ztráty dat, pak existují další alternativy, které můžete zvážit.

Jednou alternativou je funkce trvalého vyrovnávací paměti protokolu v SQL Server 2016 SP1, kde můžete vytvořit druhý 20 MB soubor protokolu transakcí na svazku úložiště v režimu přímého přístupu (DAX), který je hostován na zařízení s trvalou pamětí NV-DIMM. Tento extra soubor protokolu transakcí se používá k ukládání konce protokolu do mezipaměti s přístupem na úrovni bajtů, který obchází konvenční zásobník na úrovni bloku.

Pokud si myslíte, že by vaší pracovní zátěži mohlo prospět použití funkce trvalé vyrovnávací paměti protokolů, můžete experimentovat s dočasným použitím zpožděné trvanlivosti, abyste zjistili, zda je s vaší pracovní zátěží skutečný přínos výkonu, než utratíte peníze za trvalou paměť NV-DIMM, kterou bude muset použít funkci trvalého vyrovnávací paměti protokolu.

Přesun databáze tempdb do úložiště Intel Optane DC P4800X

Měl jsem velký úspěch s několika nedávnými klienty, kteří přesunuli své databázové soubory tempdb z jiného typu úložiště na logický disk, který byl podporován několika paměťovými kartami Intel Optane DC P4800X PCIe NVMe (v softwarovém poli RAID 1).

Tyto paměťové karty jsou k dispozici v kapacitách 375 GB, 750 GB a 1,5 TB (ačkoli kapacita 1,5 TB je zcela nová a stále je těžké ji najít). Mají extrémně nízkou latenci (mnohem nižší než jakýkoli typ NAND flash úložiště), vynikající náhodný I/O výkon při nízkých hloubkách fronty (mnohem lepší než NAND flash úložiště), s konzistentními dobami odezvy čtení při velmi vysoké zátěži zápisu.

Mají také vyšší výdrž při zápisu než podniková flash úložiště NAND s „intenzivním zápisem“ a jejich výkon se nezhoršuje, protože jsou téměř plné. Díky těmto vlastnostem jsou tyto karty mimořádně vhodné pro mnoho těžkých pracovních zátěží tempdb, zejména velké zátěže OLTP a situace, kdy používáte RCSI ve svých uživatelských databázích (což klade výslednou zátěž úložiště verzí na tempdb).

Je také velmi běžné vidět vysokou latenci zápisu na úrovni souborů u datových souborů tempdb z DMV sys.dm_io_virtual_file_stats, takže přesunutí datových souborů tempdb do úložiště Optane je jedním ze způsobů, jak tento problém přímo vyřešit, což může být rychlejší a jednodušší než konvenční ladění pracovní zátěže.

Další možné využití paměťových karet Optane je jako domov pro vaše soubory protokolu transakcí. Úložiště Optane můžete také používat se staršími verzemi SQL Serveru (pokud to váš operační systém a hardware podporuje). Je to možná alternativa k použití zpožděné trvanlivosti (která vyžaduje SQL Server 2014) nebo použití funkce trvalého vyrovnávací paměti protokolu (která vyžaduje SQL Server 2016 SP1).

Závěr

Diskutoval jsem o třech technikách, jak dosáhnout rychlého výkonu s SQL Serverem:

  • Konvenční ladění indexu úložiště řádků je použitelné pro všechny verze SQL Serveru a je to jeden z nejlepších nástrojů ve vašem arzenálu.
  • Zpožděná trvanlivost je k dispozici v SQL Server 2014 a novějších a může být velmi výhodná u některých typů zátěže (a požadavků RPO). Trvalá vyrovnávací paměť protokolu je k dispozici v SQL Server 2016 SP1 a poskytuje podobné výhody jako zpožděná trvanlivost bez nebezpečí ztráty dat.
  • Přesun určitých typů databázových souborů do úložiště Intel Optane může pomoci zmírnit problémy s výkonem databáze tempdb nebo souborů protokolu transakcí uživatelské databáze. Úložiště Optane můžete používat se staršími verzemi SQL Serveru a nejsou nutné žádné změny kódu ani konfigurace.

  1. Jak zvýšit vyrovnávací paměť dbms_output?

  2. Zadanému názvu a typům argumentů neodpovídá žádná funkce

  3. Python/postgres/psychopg2:získávání ID právě vloženého řádku

  4. Závažná chyba Wordpress:Nezachycená chyba:Volání nedefinované funkce mysql_connect() v /wp-includes/wp-db.php:1570