Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

SQL Server Automatic Tuning and sys.dm_db_tuning_recommendations

DZone's Guide to

SQL Server Automatic Tuning and sys.dm_db_tuning_recommendations

SQL Server has made available in recent versions automatic tuning! Interested to find out how it can benefit your project? Read on to find out!

· Database Zone ·
Free Resource

MariaDB TX, proven in production and driven by the community, is a complete database solution for any and every enterprise — a modern database for modern applications.

In Azure SQL Database for quite some time, and now available in SQL Server 2017, Microsoft has put a lot of the knowledge they’ve gleaned from running more databases that any of the rest of us ever will in order to work with automatic tuning.

Automatic Tuning

The core of automatic tuning at this point in time (because I’m sure it’s going to evolve) is the ability of the query engine to spot when a query has generated a new plan that is causing performance to degrade. This is known as a regression in the plan. It comes from bad parameter sniffing, changes in statistics, cumulative updates, or, the big notorious one, the cardinality estimator introduced in SQL Server 2014 (it’s been almost four years; I’m not calling it new anymore). Spotting a plan regression prior to SQL Server 2016 and the introduction of the Query Store was a major pain. However, now, it’s easy. You can spot them by reading the data collected. Further, Microsoft can spot them by reading the data collected — and it does!

If the engine sees that a plan is causing a regression (you have to have Query Store enabled for this), then it will write out a suggestion for fixing it to the new DMV, sys.dm_db_tuning_recommendations. If you further enable automatic tuning on your database, then SQL Server can automatically substitute the last good plan for you, fixing the problem. Further, SQL Server monitors this fix and if, over time, it’s clear that the forced plan is causing problems, it will unforce the plan — again, automagically.

Further, you can track the behavior of the automatic tuning by querying sys.dm_db_tuning_recommendations. It updates if it’s forced a plan or unforced a plan, and gives you all the reasons why.

sys.dm_db_tuning_recommendations

Querying the DMV itself is a snap. The issue comes from a few of the columns. The state column and the details column are both stored as JSON data. For those who know me well, you know I just had to spit on the floor after typing that. No, I do not have anything against JSON. I just hate how it has become a magic solution for all problems, everywhere. However, it has utility and programmers love it, so we’re going to be seeing it, evidently, everywhere.

JSON queries in SQL Server are pretty easy — much, much easier than XML queries — so you can readily pull the information you need. There’s only one snag: the data that returns from sys.dm_db_tuning_recommendations doesn’t include anything other than the plan_id values and the query_id value. To put together a meaningful report, you’ll have to do a little work. I’ve put together an initial example:

WITH DbTuneRec
AS (SELECT ddtr.reason,
           ddtr.score,
           pfd.query_id,
           pfd.regressedPlanId,
           pfd.recommendedPlanId,
           JSON_VALUE(ddtr.state,
                      '$.currentValue') AS CurrentState,
           JSON_VALUE(ddtr.state,
                      '$.reason') AS CurrentStateReason,
           JSON_VALUE(ddtr.details,
                      '$.implementationDetails.script') AS ImplementationScript
    FROM sys.dm_db_tuning_recommendations AS ddtr
        CROSS APPLY
        OPENJSON(ddtr.details,
                 '$.planForceDetails')
        WITH (query_id INT '$.queryId',
              regressedPlanId INT '$.regressedPlanId',
              recommendedPlanId INT '$.recommendedPlanId') AS pfd)
SELECT qsq.query_id,
       dtr.reason,
       dtr.score,
       dtr.CurrentState,
       dtr.CurrentStateReason,
       qsqt.query_sql_text,
       CAST(rp.query_plan AS XML) AS RegressedPlan,
       CAST(sp.query_plan AS XML) AS SuggestedPlan,
       dtr.ImplementationScript
FROM DbTuneRec AS dtr
    JOIN sys.query_store_plan AS rp
        ON rp.query_id = dtr.query_id
           AND rp.plan_id = dtr.regressedPlanId
    JOIN sys.query_store_plan AS sp
        ON sp.query_id = dtr.query_id
           AND sp.plan_id = dtr.recommendedPlanId
    JOIN sys.query_store_query AS qsq
        ON qsq.query_id = rp.query_id
    JOIN sys.query_store_query_text AS qsqt
        ON qsqt.query_text_id = qsq.query_text_id;

That should cover most people in most situations. You can see the query text and the plans themselves, as well as some of the more interesting bits of data from sys.dm_db_tuning_recommendations.

Conclusion

Automatic tuning really is an excellent new feature. Even if you don’t use it, you can take advantage of the information in sys.dm_db_tuning_recommendations as a starting point for adjusting your own plans. I’d suggest keeping an eye on the automatic tuning feature because it’s likely to expand to cover more of the mechanical aspects of tuning a query.

MariaDB AX is an open source database for modern analytics: distributed, columnar and easy to use.

Topics:
database ,database performance ,sql server ,automatic tuning ,database tuning ,data collection ,querying ,tutorial

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}