Comme tout DBA de production expérimenté le sait, vous êtes souvent soumis à une pression importante pour diagnostiquer et résoudre les problèmes de performances de la base de données aussi rapidement que possible. Voici trois éléments dont vous pourriez tirer parti, en fonction de votre charge de travail et de votre infrastructure, pour avoir un impact positif très notable sur les performances de votre base de données.
Réglage de base de l'index du magasin de lignes
La plupart des instances SQL Server que j'ai rencontrées au cours de ma carrière ont eu des opportunités de réglage d'index de magasin de lignes relativement faciles. Une bonne chose à propos du réglage de l'index du magasin de lignes est qu'il est plus souvent sous votre contrôle direct en tant que DBA, en particulier par rapport au réglage des requêtes ou des procédures stockées, qui sont souvent sous le contrôle de développeurs ou de fournisseurs tiers.
Certains administrateurs de bases de données hésitent à effectuer des réglages d'index (en particulier sur des bases de données tierces) car ils craignent de casser quelque chose ou de compromettre le support du fournisseur pour la base de données ou l'application. De toute évidence, vous devez être plus prudent avec les bases de données tierces et essayer de contacter le fournisseur avant d'apporter vous-même des modifications à l'index, mais dans certaines situations, vous n'avez peut-être pas d'autre alternative viable (en plus de jeter du matériel et du stockage plus rapides au problème ).
Vous pouvez exécuter quelques requêtes clés à partir de mes requêtes d'informations de diagnostic SQL Server pour avoir une bonne idée si vous pourriez avoir des opportunités de réglage d'index faciles sur votre instance ou votre base de données. Vous devez être à l'affût des demandes d'index manquantes, des avertissements d'index manquants, des index non clusterisés sous-utilisés ou non utilisés et des éventuelles opportunités de compression des données.
Il faut une certaine expérience, un bon jugement et une connaissance de votre charge de travail pour effectuer un réglage correct de l'index. Il n'est que trop courant de voir des gens effectuer un réglage incorrect de l'index, en faisant imprudemment de nombreux changements d'index sans faire l'analyse appropriée.
Voici quelques requêtes que j'aime utiliser, au niveau de la base de données :
-- 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
Utilisation de la durabilité différée
La fonctionnalité de durabilité retardée a été ajoutée au produit dans SQL Server 2014, elle est donc disponible depuis un certain temps. Les validations de transactions durables retardées sont asynchrones et signalent une validation de transaction comme réussie avant les enregistrements du journal de la transaction sont en fait écrits dans le sous-système de stockage. Les transactions durables retardées ne deviennent réellement durables que lorsque les entrées du journal des transactions sont vidées sur le disque.
Cette fonctionnalité est disponible dans toutes les éditions de SQL Server. Malgré cela, je le vois rarement utilisé lorsque je regarde les bases de données des clients. La durabilité retardée ouvre la possibilité de certaines pertes de données, jusqu'à un tampon de journal entier dans le pire des cas (comme expliqué par Paul Randal ici), donc ce n'est certainement pas approprié pour un scénario RPO où aucune perte de données n'est acceptable.
La durabilité retardée réduit la latence des transactions car elle n'attend pas que les E/S du journal se terminent et redonnent le contrôle au client, et elle réduit également le verrouillage et les conflits de disque pour les transactions simultanées. Ces deux avantages peuvent souvent avoir un effet très positif sur les performances de vos requêtes et de vos applications avec la charge de travail très lourde en écriture appropriée.
La durabilité retardée aidera le plus souvent les charges de travail lourdes de type OLTP qui ont de petites transactions d'écriture très fréquentes où vous voyez une latence d'écriture élevée au niveau du fichier de sys.dm_io_virtual_file_stats sur le fichier journal des transactions et/ou vous voyez des attentes WRITELOG élevées de sys. dm_os_wait_stats.
Vous pouvez facilement forcer SQL Server 2014 ou une version plus récente à utiliser la durabilité différée pour toutes les transactions (sans modification de code) en exécutant la commande suivante :
ALTER DATABASE AdventureWorks2014 SET DELAYED_DURABILITY = FORCED;
J'ai eu des clients qui activent et désactivent par programme la durabilité différée à différents moments de la journée (par exemple pendant l'ETL planifié ou l'activité de maintenance). J'ai également eu des clients qui utilisent la durabilité différée à tout moment car ils ont une charge de travail appropriée et une tolérance au risque de perte de données.
Enfin, j'ai eu des clients qui n'envisageraient jamais d'utiliser la durabilité différée, ou qui n'en ont tout simplement pas besoin avec leur charge de travail. Si vous pensez que votre charge de travail pourrait bénéficiez de l'utilisation de la durabilité différée, mais vous êtes préoccupé par la perte possible de données, alors il existe d'autres alternatives que vous pouvez envisager.
Une alternative est la fonctionnalité de tampon de journal persistant dans SQL Server 2016 SP1, où vous pouvez créer un deuxième fichier journal des transactions de 20 Mo sur un volume de stockage en mode d'accès direct (DAX) hébergé sur un périphérique de mémoire persistante NV-DIMM. Ce fichier journal de transactions supplémentaire est utilisé pour mettre en cache la fin du journal, avec un accès au niveau des octets qui contourne la pile de stockage conventionnelle au niveau des blocs.
Si vous pensez que votre charge de travail pourrait bénéficier de l'utilisation de la fonction de tampon de journal persistant, vous pouvez tester temporairement l'utilisation de la durabilité retardée pour voir s'il y a un avantage réel en termes de performances avec votre charge de travail avant de dépenser de l'argent sur la mémoire persistante NV-DIMM que vous aurait besoin d'utiliser la fonctionnalité de tampon de journal persistant.
Déplacement de tempdb vers le stockage Intel Optane DC P4800X
J'ai eu beaucoup de succès avec plusieurs clients récents qui ont déplacé leurs fichiers de base de données tempdb d'un autre type de stockage vers un lecteur logique soutenu par quelques cartes de stockage Intel Optane DC P4800X PCIe NVMe (dans une matrice logicielle RAID 1).
Ces cartes de stockage sont disponibles dans des capacités de 375 Go, 750 Go et 1,5 To (bien que la capacité de 1,5 To soit toute nouvelle et toujours difficile à trouver). Ils ont une latence extrêmement faible (bien inférieure à tout type de stockage flash NAND), d'excellentes performances d'E/S aléatoires à faible profondeur de file d'attente (bien meilleures que le stockage flash NAND), avec des temps de réponse en lecture constants sous une charge de travail d'écriture très lourde.
Ils ont également une endurance en écriture plus élevée que le stockage flash NAND d'entreprise "intensif en écriture", et leurs performances ne se détériorent pas car ils sont presque pleins. Ces caractéristiques rendent ces cartes extrêmement bien adaptées à de nombreuses charges de travail tempdb lourdes, en particulier aux charges de travail OLTP lourdes et aux situations où vous utilisez RCSI dans vos bases de données utilisateur (ce qui place la charge de travail du magasin de versions résultante sur tempdb).
Il est également très courant de voir une latence d'écriture élevée au niveau des fichiers sur les fichiers de données tempdb à partir du DMV sys.dm_io_virtual_file_stats. réglage de la charge de travail.
Une autre utilisation possible des cartes de stockage Optane est de stocker vos fichiers journaux de transactions. Vous pouvez également utiliser le stockage Optane avec les anciennes versions de SQL Server (à condition que votre système d'exploitation et votre matériel le prennent en charge). Il s'agit d'une alternative possible à l'utilisation de la durabilité différée (qui nécessite SQL Server 2014) ou à l'utilisation de la fonctionnalité de tampon de journal persistant (qui nécessite SQL Server 2016 SP1).
Conclusion
J'ai discuté de trois techniques pour gagner rapidement des performances avec SQL Server :
- Le réglage conventionnel des index de magasin de lignes s'applique à toutes les versions de SQL Server et constitue l'un des meilleurs outils de votre arsenal.
- La durabilité différée est disponible dans SQL Server 2014 et versions ultérieures, et peut être très bénéfique avec certains types de charges de travail (et exigences RPO). Le tampon de journal persistant est disponible dans SQL Server 2016 SP1 et offre des avantages similaires à ceux de la durabilité retardée, sans risque de perte de données.
- Le déplacement de certains types de fichiers de base de données vers le stockage Intel Optane peut aider à atténuer les problèmes de performances avec tempdb ou avec les fichiers journaux des transactions de la base de données utilisateur. Vous pouvez utiliser le stockage Optane avec les anciennes versions de SQL Server, et aucune modification de code ou de configuration n'est requise.