sql >> Base de Datos >  >> RDS >> Sqlserver

Tres sencillas victorias en el rendimiento de SQL Server

Como sabe cualquier DBA de producción veterano, a menudo se encuentra bajo una gran presión para diagnosticar y aliviar los problemas de rendimiento de la base de datos lo más rápido posible. Aquí hay tres cosas que podría aprovechar, dependiendo de su carga de trabajo e infraestructura, para tener un impacto positivo muy notable en el rendimiento de su base de datos.

Ajuste básico del índice de almacenamiento de filas

La mayoría de las instancias de SQL Server que he encontrado en mi carrera han tenido algunas oportunidades de ajuste del índice de almacenamiento de filas relativamente fáciles. Una cosa buena sobre el ajuste del índice de almacenamiento de filas es que, con mayor frecuencia, está bajo su control directo como DBA, especialmente en comparación con el ajuste de consultas o procedimientos almacenados, que a menudo están bajo el control de desarrolladores o proveedores externos.

Algunos administradores de bases de datos son reacios a realizar cualquier ajuste de índice (especialmente en bases de datos de terceros) porque les preocupa romper algo o poner en peligro el soporte del proveedor para la base de datos o la aplicación. Obviamente, debe tener más cuidado con las bases de datos de terceros e intentar comunicarse con el proveedor antes de realizar cualquier cambio en el índice usted mismo, pero en algunas situaciones, es posible que no tenga otra alternativa viable (además de arrojar hardware y almacenamiento más rápidos al problema). ).

Puede ejecutar algunas consultas clave de mis Consultas de información de diagnóstico de SQL Server para tener una buena idea si puede tener algunas oportunidades fáciles de ajuste de índice en su instancia o base de datos. Debe estar atento a las solicitudes de índice faltantes, las advertencias de índice faltantes, los índices no agrupados infrautilizados o no utilizados y las posibles oportunidades de compresión de datos.

Se necesita algo de experiencia, buen juicio y conocimiento de su carga de trabajo para realizar un ajuste de índice adecuado. Es muy común ver a las personas realizar un ajuste de índice incorrecto, al realizar muchos cambios de índice sin realizar el análisis adecuado.

Aquí hay algunas consultas que me gusta usar, a nivel de base de datos:

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

Uso de durabilidad retardada

La función de durabilidad retrasada se agregó al producto en SQL Server 2014, por lo que ha estado disponible durante bastante tiempo. Las confirmaciones de transacciones duraderas retrasadas son asincrónicas y notifican una confirmación de transacción como exitosa antes los registros de registro de la transacción se escriben realmente en el subsistema de almacenamiento. Las transacciones duraderas retrasadas en realidad no se vuelven duraderas hasta que las entradas del registro de transacciones se descargan en el disco.

Esta función está disponible en todas las ediciones de SQL Server. A pesar de esto, rara vez veo que se use cuando miro las bases de datos de los clientes. La durabilidad retrasada abre la posibilidad de alguna pérdida de datos, hasta un búfer de registro completo en el peor de los casos (como lo explica Paul Randal aquí), por lo que definitivamente no es apropiado para un escenario de RPO donde absolutamente ninguna pérdida de datos es aceptable.

La durabilidad retrasada reduce la latencia de las transacciones porque no espera a que finalice el registro de E/S y devuelva el control al cliente, y también reduce el bloqueo y la contención del disco para transacciones simultáneas. Estos dos beneficios a menudo pueden tener un efecto muy positivo en su consulta y el rendimiento de la aplicación con la carga de trabajo de escritura muy pesada adecuada.

La durabilidad retrasada generalmente ayudará a las cargas de trabajo pesadas de tipo OLTP que tienen transacciones de escritura pequeñas y muy frecuentes en las que observa una latencia de escritura de nivel de archivo alta de sys.dm_io_virtual_file_stats en el archivo de registro de transacciones y/o está viendo esperas altas de WRITELOG de sys. dm_os_wait_stats.

Puede obligar fácilmente a SQL Server 2014 o posterior a usar la durabilidad retrasada para todas las transacciones (sin cambios de código) ejecutando el siguiente comando:

ALTER DATABASE AdventureWorks2014 SET DELAYED_DURABILITY = FORCED;

He tenido clientes que activan y desactivan programáticamente la durabilidad retrasada en diferentes momentos del día (como durante la ETL programada o la actividad de mantenimiento). También he tenido clientes que utilizan la durabilidad diferida en todo momento ya que tienen una carga de trabajo adecuada y tolerancia al riesgo de pérdida de datos.

Finalmente, he tenido clientes que nunca considerarían usar durabilidad diferida, o simplemente no la necesitan con su carga de trabajo. Si sospecha que su carga de trabajo podría beneficiarse del uso de la durabilidad retrasada, pero le preocupa la posible pérdida de datos, entonces hay otras alternativas que puede considerar.

Una alternativa es la función de búfer de registro persistente en SQL Server 2016 SP1, donde puede crear un segundo archivo de registro de transacciones de 20 MB en un volumen de almacenamiento de modo de acceso directo (DAX) alojado en un dispositivo de memoria persistente NV-DIMM. Este archivo de registro de transacciones adicional se usa para almacenar en caché la parte final del registro, con acceso a nivel de byte que pasa por alto la pila de almacenamiento convencional a nivel de bloque.

Si cree que su carga de trabajo podría beneficiarse del uso de la función de búfer de registro persistente, puede experimentar con el uso temporal de durabilidad retrasada para ver si hay un beneficio de rendimiento real con su carga de trabajo antes de gastar el dinero en la memoria persistente NV-DIMM que necesita. necesitaría usar la función de búfer de registro persistente.

Traslado de tempdb al almacenamiento Intel Optane DC P4800X

He tenido un gran éxito con varios clientes recientes que movieron sus archivos de base de datos tempdb de algún otro tipo de almacenamiento a una unidad lógica respaldada por un par de tarjetas de almacenamiento Intel Optane DC P4800X PCIe NVMe (en una matriz de software RAID 1).

Estas tarjetas de almacenamiento están disponibles en capacidades de 375 GB, 750 GB y 1,5 TB (aunque la capacidad de 1,5 TB es nueva y todavía es difícil de encontrar). Tienen una latencia extremadamente baja (mucho más baja que cualquier tipo de almacenamiento flash NAND), un rendimiento de E/S aleatorio excelente a profundidades de cola bajas (mucho mejor que el almacenamiento flash NAND), con tiempos de respuesta de lectura uniformes bajo una carga de trabajo de escritura muy pesada.

También tienen una resistencia de escritura más alta que el almacenamiento flash NAND empresarial de "escritura intensiva", y su rendimiento no se deteriora cuando están cerca de estar llenos. Estas características hacen que estas tarjetas sean extremadamente adecuadas para muchas cargas de trabajo pesadas de tempdb, particularmente cargas de trabajo pesadas de OLTP y situaciones en las que utiliza RCSI en sus bases de datos de usuario (lo que coloca la carga de trabajo del almacén de versiones resultante en tempdb).

También es muy común ver una alta latencia de escritura a nivel de archivo en los archivos de datos tempdb del DMV sys.dm_io_virtual_file_stats, por lo que mover sus archivos de datos tempdb al almacenamiento de Optane es una forma de abordar directamente ese problema, que podría ser más rápido y más fácil que lo convencional. ajuste de la carga de trabajo.

Otro posible uso de las tarjetas de almacenamiento Optane es como hogar para sus archivos de registro de transacciones. También puede usar el almacenamiento Optane con versiones heredadas de SQL Server (siempre que su sistema operativo y hardware lo admitan). Es una posible alternativa al uso de durabilidad retrasada (que requiere SQL Server 2014) o al uso de la función de búfer de registro persistente (que requiere SQL Server 2016 SP1).

Conclusión

Discutí tres técnicas para obtener una ganancia rápida de rendimiento con SQL Server:

  • El ajuste convencional del índice de almacenamiento de filas se aplica a todas las versiones de SQL Server y es una de las mejores herramientas de su arsenal.
  • La durabilidad retrasada está disponible en SQL Server 2014 y versiones posteriores, y puede ser muy beneficiosa con algunos tipos de carga de trabajo (y requisitos de RPO). El búfer de registro persistente está disponible en SQL Server 2016 SP1 y brinda beneficios similares a la durabilidad retrasada, sin el peligro de pérdida de datos.
  • Mover ciertos tipos de archivos de base de datos al almacenamiento Intel Optane puede ayudar a aliviar los problemas de rendimiento con tempdb o con los archivos de registro de transacciones de la base de datos del usuario. Puede usar el almacenamiento de Optane con versiones heredadas de SQL Server y no se requieren cambios de código o configuración.