2016-02-17 33 views
6

Użyliśmy User-Defined Table Types do przekazania listy liczb całkowitych do naszych procedur składowanych.Wydajność typów tabel zdefiniowanych przez użytkownika w SQL Server

Następnie używamy ich do dołączania do innych tabel w naszych przechowywanych zapytaniach proc.

Na przykład:

CREATE PROCEDURE [dbo].[sp_Name] 
(
    @Ids [dbo].[OurTableType] READONLY 
) 
AS 
    SET Nocount ON 

    SELECT 
     * 
    FROM 
     SOMETABLE 
     INNER JOIN @Ids [OurTableType] ON [OurTableType].Id = SOMETABLE.Id 

Widzieliśmy bardzo słabą wydajność podczas korzystania z tego większych zbiorów danych.

Jednym ze sposobów, w jaki przyspieszyliśmy działania, jest zrzucenie zawartości do tymczasowego stołu i połączenie zamiast tego.

Na przykład:

CREATE PROCEDURE [dbo].[sp_Name] 
(
    @Ids [dbo].[OurTableType] READONLY 
) 
AS 
    SET Nocount ON 
    CREATE TABLE #TempTable(Id INT) 
    INSERT INTO #TempTable 
    SELECT Id from @Ids 

    SELECT 
     * 
    FROM 
     SOMETABLE 
     INNER JOIN #TempTable ON #TempTable.Id = SOMETABLE.Id 

    DROP TABLE #TempTable 

ta ma znacznie poprawić wydajność, ale chciałem uzyskać jakieś opinie na temat tego podejścia i jakiekolwiek inne konsekwencje nie są brane pod uwagę. Pomocne może być również wyjaśnienie, dlaczego poprawia to wydajność.

N.B. czasami możemy potrzebować przekazać więcej niż liczbę całkowitą, dlatego nie używamy listy rozdzielanej przecinkami lub czegoś podobnego.

+0

pytanie: czy przechodzisz na tę listę z warstwy aplikacji, czy innego sproca? istnieje wiele artykułów na temat tabel tymczasowych a zmiennych tabel. http: // stackoverflow.com/questions/27894/whats-the-difference-between-a-temp-table-and-table-variable-in-sql-server i http://www.sql-server-performance.com/2007/temp- tables-vs-variables/ – Jeremy

+0

Tak, przekazujemy listę z warstwy aplikacji. Dzięki za artykuły. – KMB

Odpowiedz

7

Ten temat został omówiony wcześniej. Główną przyczyną słabej wydajności JOIN jest to, że parametr wartościowania tabelowego (TVP) jest zmienną tabelową. Zmienne tabeli nie przechowują statystyk i pojawiają się w Optymalizatorze zapytań, aby mieć tylko jeden wiersz. W związku z tym są one w porządku, aby zrobić coś takiego, jak INSERT INTO Table (column_list) SELECT column_list FROM @TVP;, ale nie JOIN.

Istnieje kilka rzeczy, aby spróbować obejść ten problem:

  1. Dump wszystko do lokalnej tabeli tymczasowej (jesteś już to robi). Techniczną wadą jest to, że powielacie dane przekazywane do TVP w tempdb (gdzie zarówno TVP, jak i tabela tymczasowa przechowują swoje dane).

  2. Być może spróbuj zdefiniować typ tabeli zdefiniowany przez użytkownika, aby uzyskać klastrowy klucz podstawowy. Można to zrobić na polu inline [Id]:

    [ID] INT NOT NULL PRIMARY KEY 
    

    Nie wiem ile to pomaga wydajność, ale warto spróbować.

  3. Możesz spróbować dodać OPTION (RECOMPILE) do zapytania. Jest to sposób na uzyskanie Optymalizatora zapytań, aby sprawdzić, ile wierszy znajduje się w Zmiennej tabeli, aby mógł on mieć właściwe oszacowania.

    SELECT column_list 
    FROM SOMETABLE 
    INNER JOIN @Ids [OurTableType] 
         ON [OurTableType].Id = SOMETABLE.Id 
    OPTION (RECOMPILE); 
    

    Wadą jest to, że masz RECOMPILE, który zabiera dodatkowy czas za każdym razem, gdy wywoływany jest ten proces. Ale może to być ogólny zysk netto.

PS. Nie rób tego SELECT *. Zawsze określaj listę kolumn. Chyba że robisz coś takiego jak IF EXIST(SELECT * FROM)....

+0

Dzięki za sugestię przetestowaliśmy 2 i 3 z pewną poprawą. Jednak opcja 1 jest nadal najszybsza w tym przypadku. Rozumiem koszty związane z powielaniem danych. – KMB