Aracılığıyla paylaş


Plan zorlama senaryosu: Yeniden bir sorgudan alınan bir Plan zorlamak için bir Plan kılavuz oluşturmak

Sık sık sorgu için geliştirilmiş bir planı elde etmek için en uygun sorgu sorgu mantıksal anlamını değiştirmeden Sorgu ipuçları kullanarak birleştirmek sırasını, birleştirmek algoritmalar veya dizin kullanımını zorlamak için el ile yeniden yazmak için yoludur.Sorgu içinde dağıtılmış bir uygulama ise, ancak, bu yöntem kullanılabilir olmayabilir.Plan kılavuzları kullanarak bu durumda yardımcı olabilir.Çalışma kılavuzları olası veya doğrudan sorgu metnini değiştirmek için uygun olmadığında sorgu ipuçları veya sorgu planları sorguları ekleyerek planlayın.Daha fazla bilgi için bkz: Plan kılavuzları kullanarak sorgular dağıtılan uygulamalar içinde en iyi duruma getirme.

El ile bir sorgu el ile yeniden plandan yakalamak ve sonra özgün sorgu yakalanan planı içeren bir plan Kılavuzu ile yakalanan planı uygulamak için bu işlemi izleyin:

  1. Sorguyu değiştirmek nasıl belirlenir (force order, birleştirmek ipuçları veya dizin ipuçlarını kullanarak, birleştirmek sırasını değiştirerek ve başka teknikler kullanan), böylece iyi bir plan üretilen ancak sorgunun mantıksal anlamı değişti.

  2. Yalnızca özgün sorgu gibi gönderilen yeniden sorgu planı yakalama (gibi kullanarak sp_executesql, sp_cursorprepexec, ya da tek başına bir toplu iş olarak).

  3. Özgün sorgu alınan iyi plan zorlamak için bir plan Kılavuzu oluşturun.

  4. Kullanarak SQL Server Profiler, select Plan Kılavuzu başarılı ve Plan Kılavuzu başarısız olaylar Performans kategorisini ve sonra da özgün sorguyu çalıştırın.İnceleme SQL Server Profiler sorguyu kullandığını doğrulamak için plan kılavuzu.

Örnek

Aşağıdaki sorgu çok yavaş bir sorgu planı oluşturur varsayalım.

USE AdventureWorks2008R2;
GO
EXEC sp_executesql 
@stmt = N'SELECT soh.SalesPersonID
   ,p.FirstName + '' '' + COALESCE(p.MiddleName, '''') + '' '' + p.LastName AS FullName
   ,e.JobTitle
   ,st.Name AS SalesTerritory
    ,soh.SubTotal
    ,YEAR(DATEADD(m, 6, soh.OrderDate)) AS FiscalYear 
    FROM Sales.SalesPerson AS sp 
    INNER JOIN Sales.SalesOrderHeader AS soh ON sp.BusinessEntityID = soh.SalesPersonID
    INNER JOIN Sales.SalesTerritory AS st ON sp.TerritoryID = st.TerritoryID
    INNER JOIN HumanResources.Employee AS e ON soh.SalesPersonID = e.BusinessEntityID 
    INNER JOIN Person.Person AS p ON e.BusinessEntityID = p.BusinessEntityID
    WHERE st.[Group] = @p1', 
@params = N'@p1 nvarchar(80)',
@p1 = N'North America';
GO

Aşağıdaki şekilde mantıksal olarak aynı olmasını sorgu yazabilirsiniz ancak farklı birleştirmek sipariş ile hangi zorlanır.

USE AdventureWorks2008R2;
GO
EXEC sp_executesql 
@stmt = N'SELECT
    soh.SalesPersonID
    ,p.FirstName + '' '' + COALESCE(p.MiddleName, '''') + '' '' + p.LastName AS FullName
    ,e.JobTitle
    ,st.Name AS SalesTerritory
    ,soh.SubTotal
    ,YEAR(DATEADD(m, 6, soh.OrderDate)) AS FiscalYear 
    FROM Sales.SalesPerson sp 
    INNER JOIN Sales.SalesOrderHeader soh ON sp.BusinessEntityID = soh.SalesPersonID
    INNER JOIN Sales.SalesTerritory st ON sp.TerritoryID = st.TerritoryID
    INNER JOIN HumanResources.Employee e ON soh.SalesPersonID = e.BusinessEntityID 
    INNER JOIN Person.Person p ON e.BusinessEntityID = p.BusinessEntityID
    WHERE st.[Group] = @p1
    OPTION (FORCE ORDER)', 
@params = N'@p1 nvarchar(80)',
@p1 = N'North America';
GO

Özgün sorguyu yeniden sorgu planı zorlamak için bir plan kılavuz oluşturmak için bir değişken planında yakalamak ve plan Kılavuzu'nda değişken belirtmek deyim aşağıdaki kodda gösterildiği gibi.

DBCC FREEPROCCACHE;
GO
USE AdventureWorks2008R2;
GO
EXEC sp_executesql 
@stmt = N'SELECT
    soh.SalesPersonID
    ,p.FirstName + '' '' + COALESCE(p.MiddleName, '''') + '' '' + p.LastName AS FullName
    ,e.JobTitle
    ,st.Name AS SalesTerritory
    ,soh.SubTotal
    ,YEAR(DATEADD(m, 6, soh.OrderDate)) AS FiscalYear 
    FROM Sales.SalesPerson sp 
    INNER JOIN Sales.SalesOrderHeader AS soh ON sp.BusinessEntityID = soh.SalesPersonID
    INNER JOIN Sales.SalesTerritory AS st ON sp.TerritoryID = st.TerritoryID
    INNER JOIN HumanResources.Employee AS e ON soh.SalesPersonID = e.BusinessEntityID 
    INNER JOIN Person.Person AS p ON e.BusinessEntityID = p.BusinessEntityID
    WHERE st.[Group] = @p1
    OPTION (FORCE ORDER)', 
@params = N'@p1 nvarchar(80)',
@p1 = N'North America';
GO

DECLARE @xml_showplan nvarchar(max);
SET @xml_showplan = (SELECT query_plan
    FROM sys.dm_exec_query_stats AS qs 
    CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st
    CROSS APPLY sys.dm_exec_text_query_plan(qs.plan_handle, DEFAULT, DEFAULT) AS qp
    WHERE st.text LIKE N'%Sales.SalesPerson%' AND st.text LIKE N'%OPTION (FORCE ORDER)%');

EXEC sp_create_plan_guide
@name = N'ForceOrderGuide1',
@stmt = N'SELECT
    soh.SalesPersonID
    ,p.FirstName + '' '' + COALESCE(p.MiddleName, '''') + '' '' + p.LastName AS FullName
    ,e.JobTitle
    ,st.Name AS SalesTerritory
    ,soh.SubTotal
    ,YEAR(DATEADD(m, 6, soh.OrderDate)) AS FiscalYear 
    FROM Sales.SalesPerson AS sp 
    INNER JOIN Sales.SalesOrderHeader AS soh ON sp.BusinessEntityID = soh.SalesPersonID
    INNER JOIN Sales.SalesTerritory ASst ON sp.TerritoryID = st.TerritoryID
    INNER JOIN HumanResources.Employee ASe ON soh.SalesPersonID = e.BusinessEntityID 
    INNER JOIN Person.Person ASp ON e.BusinessEntityID = p.BusinessEntityID
    WHERE st.[Group] = @p1', 
@type = N'SQL',
@module_or_batch = NULL,
@params = N'@p1 nvarchar(80)',
@hints = @xml_showplan;

GO
SELECT * FROM sys.plan_guides;
GO

Özgün sorguyu çalıştırmadan önce bir izleme oluşturmak SQL Server Profiler ve olayları seçin Plan Kılavuzu başarılı ve Plan Kılavuzu başarısız dan Performans kategori.Özgün sorguyu çalıştırabilir ve doğrulamak sonuçlar sorgunun çıktısı olarak izleme.

USE AdventureWorks2008R2;
GO
EXEC sp_executesql 
@stmt = N'SELECT
    soh.SalesPersonID
    ,p.FirstName + '' '' + COALESCE(p.MiddleName, '''') + '' '' + p.LastName AS FullName
    ,e.JobTitle
    ,st.Name AS SalesTerritory
    ,soh.SubTotal
    ,YEAR(DATEADD(m, 6, soh.OrderDate)) AS FiscalYear 
    FROM Sales.SalesPerson AS sp 
    INNER JOIN Sales.SalesOrderHeader AS soh ON sp.BusinessEntityID = soh.SalesPersonID
    INNER JOIN Sales.SalesTerritory ASst ON sp.TerritoryID = st.TerritoryID
    INNER JOIN HumanResources.Employee ASe ON soh.SalesPersonID = e.BusinessEntityID 
    INNER JOIN Person.Person AS p ON e.BusinessEntityID = p.BusinessEntityID
    WHERE st.[Group] = @p1', 
@params = N'@p1 nvarchar(80)',
@p1 = N'North America';
GO