Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Tre facili vittorie in termini di prestazioni di SQL Server

Come ogni DBA veterano della produzione sa, si è spesso sottoposti a forti pressioni per diagnosticare e alleviare i problemi di prestazioni del database il più rapidamente possibile. Ecco tre cose che potresti sfruttare, a seconda del tuo carico di lavoro e dell'infrastruttura, per avere un impatto positivo molto evidente sulle prestazioni del tuo database.

Regolazione dell'indice di base del negozio di righe

La maggior parte delle istanze di SQL Server che ho incontrato nella mia carriera hanno avuto alcune opportunità di ottimizzazione dell'indice dell'archivio di righe relativamente facili. Un aspetto positivo dell'ottimizzazione dell'indice dell'archivio di righe è che è più spesso sotto il tuo controllo diretto come DBA, soprattutto rispetto all'ottimizzazione di query o stored procedure, che sono spesso sotto il controllo di sviluppatori o fornitori di terze parti.

Alcuni DBA sono riluttanti a eseguire qualsiasi ottimizzazione dell'indice (soprattutto su database di terze parti) perché sono preoccupati di rompere qualcosa o mettere a repentaglio il supporto del fornitore per il database o l'applicazione. Ovviamente, devi stare più attento con i database di terze parti e provare a contattare il fornitore prima di apportare tu stesso qualsiasi modifica all'indice, ma in alcune situazioni potresti non avere altra valida alternativa (oltre a lanciare hardware e storage più veloci al problema ).

Puoi eseguire alcune query chiave dalle mie query di informazioni diagnostiche di SQL Server per avere una buona idea se potresti avere alcune semplici opportunità di ottimizzazione dell'indice sulla tua istanza o database. Dovresti prestare attenzione a richieste di indici mancanti, avvisi di indici mancanti, indici non cluster utilizzati o non utilizzati e possibili opportunità di compressione dei dati.

Sono necessari un po' di esperienza, buon senso e conoscenza del carico di lavoro per eseguire una corretta ottimizzazione dell'indice. È fin troppo comune vedere persone che mettono a punto in modo errato l'indice, apportando avventatamente molte modifiche all'indice senza eseguire l'analisi corretta.

Ecco alcune query che mi piace utilizzare, a livello di database:

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

Utilizzo della durata ritardata

La funzionalità di durabilità ritardata è stata aggiunta al prodotto in SQL Server 2014, quindi è disponibile da un po' di tempo. I commit di transazione durevoli ritardati sono asincroni e segnalano un commit di transazione come riuscito prima i record di registro per la transazione vengono effettivamente scritti nel sottosistema di archiviazione. Le transazioni durevoli ritardate non diventano effettivamente durevoli fino a quando le voci del registro delle transazioni non vengono scaricate su disco.

Questa funzionalità è disponibile in tutte le edizioni di SQL Server. Nonostante ciò, lo vedo raramente utilizzato quando guardo i database dei client. La durabilità ritardata apre la possibilità di una certa perdita di dati, fino a un intero buffer di registro nello scenario peggiore (come spiegato qui da Paul Randal), quindi non è assolutamente appropriato per uno scenario RPO in cui non è assolutamente accettabile alcuna perdita di dati.

La durabilità ritardata riduce la latenza delle transazioni perché non attende il completamento dell'IO del registro e restituisce il controllo al client e riduce anche il blocco e la contesa del disco per le transazioni simultanee. Questi due vantaggi possono spesso avere un effetto molto positivo sulla query e sulle prestazioni dell'applicazione con il carico di lavoro appropriato e molto pesante in scrittura.

La durabilità ritardata molto spesso aiuta carichi di lavoro pesanti di tipo OLTP che hanno transazioni di scrittura molto frequenti e di piccole dimensioni in cui si vede un'elevata latenza di scrittura a livello di file da sys.dm_io_virtual_file_stats sul file di registro delle transazioni e/o si verificano attese WRITELOG elevate da sys. dm_os_wait_stats.

Puoi forzare facilmente SQL Server 2014 o versioni successive a utilizzare la durabilità ritardata per tutte le transazioni (senza modifiche al codice) eseguendo il comando seguente:

ALTER DATABASE AdventureWorks2014 SET DELAYED_DURABILITY = FORCED;

Ho avuto clienti che attivano e disattivano in modo programmatico la durabilità ritardata in diversi momenti della giornata (ad esempio durante l'ETL programmato o l'attività di manutenzione). Ho anche avuto clienti che utilizzano sempre la durabilità ritardata poiché hanno un carico di lavoro appropriato e una tolleranza al rischio di perdita di dati.

Infine, ho avuto clienti che non avrebbero mai preso in considerazione l'utilizzo della durabilità ritardata o semplicemente non ne hanno bisogno con il loro carico di lavoro. Se sospetti che il tuo carico di lavoro potrebbe trarre vantaggio dall'utilizzo della durabilità ritardata, ma sei preoccupato per la possibile perdita di dati, quindi ci sono altre alternative che puoi prendere in considerazione.

Un'alternativa è la funzionalità del buffer di registro persistente in SQL Server 2016 SP1, in cui è possibile creare un secondo file di registro delle transazioni da 20 MB in un volume di archiviazione in modalità di accesso diretto (DAX) ospitato in un dispositivo di memoria persistente NV-DIMM. Questo file di registro delle transazioni aggiuntivo viene utilizzato per memorizzare nella cache la coda del registro, con un accesso a livello di byte che ignora lo stack di archiviazione a livello di blocco convenzionale.

Se ritieni che il tuo carico di lavoro possa trarre vantaggio dall'utilizzo della funzione di buffer di registro persistente, puoi provare a utilizzare temporaneamente la durabilità ritardata per vedere se c'è un effettivo vantaggio in termini di prestazioni con il tuo carico di lavoro prima di spendere i soldi per la memoria persistente NV-DIMM che hai dovrebbe utilizzare la funzione di buffer di registro persistente.

Spostamento di tempdb in Intel Optane DC P4800X Storage

Ho avuto un grande successo con diversi client recenti che hanno spostato i loro file di database tempdb da un altro tipo di archiviazione a un'unità logica supportata da un paio di schede di archiviazione Intel Optane DC P4800X PCIe NVMe (in un array RAID 1 software).

Queste schede di memoria sono disponibili con capacità da 375 GB, 750 GB e 1,5 TB (sebbene la capacità di 1,5 TB sia nuova di zecca e ancora difficile da trovare). Hanno una latenza estremamente bassa (molto inferiore a qualsiasi tipo di memoria flash NAND), eccellenti prestazioni di I/O casuale a basse profondità di coda (molto migliori di una memoria flash NAND), con tempi di risposta di lettura coerenti con un carico di lavoro di scrittura molto pesante.

Hanno anche una maggiore resistenza in scrittura rispetto allo storage flash NAND aziendale "ad alta intensità di scrittura" e le loro prestazioni non si deteriorano poiché sono quasi esaurite. Queste caratteristiche rendono queste schede estremamente adatte per molti carichi di lavoro tempdb pesanti, carichi di lavoro OLTP particolarmente pesanti e situazioni in cui si utilizza RCSI nei database degli utenti (che inserisce il carico di lavoro dell'archivio versioni risultante su tempdb).

È anche molto comune vedere un'elevata latenza di scrittura a livello di file sui file di dati tempdb dal DMV sys.dm_io_virtual_file_stats, quindi spostare i file di dati tempdb nell'archiviazione Optane è un modo per risolvere direttamente questo problema, che potrebbe essere più rapido e semplice rispetto ai tradizionali ottimizzazione del carico di lavoro.

Un altro possibile utilizzo delle schede di memoria Optane è come una casa per i file di registro delle transazioni. Puoi anche usare l'archiviazione Optane con versioni legacy di SQL Server (purché il tuo sistema operativo e hardware lo supportino). È una possibile alternativa all'utilizzo della durabilità ritardata (che richiede SQL Server 2014) o all'utilizzo della funzionalità del buffer di registro persistente (che richiede SQL Server 2016 SP1).

Conclusione

Ho discusso tre tecniche per ottenere una rapida vittoria in termini di prestazioni con SQL Server:

  • L'ottimizzazione dell'indice dell'archivio righe convenzionale è applicabile a tutte le versioni di SQL Server ed è uno dei migliori strumenti del tuo arsenale.
  • La durabilità ritardata è disponibile in SQL Server 2014 e versioni successive e può essere molto vantaggiosa con alcuni tipi di carico di lavoro (e requisiti RPO). Il buffer di log persistente è disponibile in SQL Server 2016 SP1 e offre vantaggi simili alla durabilità ritardata, senza pericolo di perdita di dati.
  • Lo spostamento di determinati tipi di file di database nell'archiviazione Intel Optane può aiutare ad alleviare i problemi di prestazioni con tempdb o con i file di registro delle transazioni del database dell'utente. Puoi utilizzare l'archiviazione Optane con le versioni precedenti di SQL Server e non sono necessarie modifiche al codice o alla configurazione.