Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

Kinerja penerapan luar dengan fungsi

Itu tergantung dari jenis fungsi:

  1. Jika fungsinya adalah fungsi bernilai tabel sebaris, maka fungsi ini akan dianggap sebagai tampilan "berparameter" dan SQL Server dapat melakukan beberapa pekerjaan pengoptimalan.

  2. Jika fungsinya adalah fungsi bernilai tabel multi-langkah maka sulit untuk SQL Server untuk mengoptimalkan pernyataan dan output dari SET STATISTICS IO akan menyesatkan.

Untuk pengujian selanjutnya saya menggunakan AdventureWorks2008 (Anda dapat mengunduh database ini dari CodePlex). Dalam database contoh ini, Anda mungkin menemukan inline table-valued function bernama [Sales].[ufnGetCheapestProduct] :

ALTER FUNCTION [Sales].[ufnGetCheapestProduct](@ProductID INT)
RETURNS TABLE
AS
RETURN
    SELECT   dt.ProductID
            ,dt.UnitPrice
    FROM
    (
        SELECT   d.SalesOrderDetailID
                ,d.UnitPrice
                ,d.ProductID  
                ,ROW_NUMBER() OVER(PARTITION BY d.ProductID ORDER BY d.UnitPrice ASC, d.SalesOrderDetailID) RowNumber
        FROM    Sales.SalesOrderDetail d
        WHERE   d.ProductID = @ProductID
    ) dt
    WHERE   dt.RowNumber = 1

Saya membuat fungsi baru bernama [Sales].[ufnGetCheapestProductMultiStep] . Fungsi ini adalah multi-step table-valued function :

CREATE FUNCTION [Sales].[ufnGetCheapestProductMultiStep](@ProductID INT)
RETURNS @Results TABLE (ProductID INT PRIMARY KEY, UnitPrice MONEY NOT NULL)
AS
BEGIN
    INSERT  @Results(ProductID, UnitPrice)
    SELECT   dt.ProductID
            ,dt.UnitPrice
    FROM
    (
        SELECT   d.SalesOrderDetailID
                ,d.UnitPrice
                ,d.ProductID  
                ,ROW_NUMBER() OVER(PARTITION BY d.ProductID ORDER BY d.UnitPrice ASC, d.SalesOrderDetailID) RowNumber
        FROM    Sales.SalesOrderDetail d
        WHERE   d.ProductID = @ProductID
    ) dt
    WHERE   dt.RowNumber = 1;

    RETURN;
END

Sekarang, kita dapat menjalankan tes berikutnya:

--Test 1
SELECT  p.ProductID, p.Name, oa1.*
FROM    Production.Product p
OUTER APPLY 
(
    SELECT   dt.ProductID
            ,dt.UnitPrice
    FROM
    (
        SELECT   d.SalesOrderDetailID
                ,d.UnitPrice
                ,d.ProductID  
                ,ROW_NUMBER() OVER(PARTITION BY d.ProductID ORDER BY d.UnitPrice ASC, d.SalesOrderDetailID) RowNumber
        FROM    Sales.SalesOrderDetail d
        WHERE   d.ProductID = p.ProductID
    ) dt
    WHERE   dt.RowNumber = 1
) oa1

--Test 2
SELECT  p.ProductID, p.Name, oa2.*
FROM    Production.Product p
OUTER APPLY [Sales].[ufnGetCheapestProduct](p.ProductID) oa2

--Test 3
SELECT  p.ProductID, p.Name, oa3.*
FROM    Production.Product p
OUTER APPLY [Sales].[ufnGetCheapestProductMultiStep](p.ProductID) oa3

Dan ini adalah output dari SQL Profiler :

Kesimpulan :Anda dapat melihatnya menggunakan kueri atau fungsi bernilai tabel sebaris dengan OUTER APPLY akan memberi Anda kinerja yang sama (pembacaan logis). Plus:fungsi bernilai tabel multi-langkah (biasanya) lebih mahal .

Catatan :Saya tidak menyarankan menggunakan SET STATISTICS IO untuk mengukur IO untuk skalar dan tabel multi-langkah bernilai fungsi karena hasilnya bisa salah. Misalnya, untuk pengujian ini output dari SET STATISTICS IO ON akan menjadi:

--Test 1
Table 'SalesOrderDetail'. Scan count 504, logical reads 1513, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Product'. Scan count 1, logical reads 5, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

--Test 2
Table 'SalesOrderDetail'. Scan count 504, logical reads 1513, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Product'. Scan count 1, logical reads 5, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

--Test 3
Table '#064EAD61'. Scan count 504, logical reads 1008 /*WRONG*/, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Product'. Scan count 1, logical reads 5, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Pagination di SQL Server menggunakan OFFSET/FETCH

  2. Ambil Nama Parameter &Nilai Saat Ini Secara Dinamis Di Dalam Prosedur Tersimpan T-SQL

  3. Tahu-Cara Mengembalikan Catatan yang Dihapus di SQL Server

  4. cara mengenkripsi kolom kata sandi

  5. SQL Server 2016:Sisipkan Data