Переменная таблицы в SQL Server - PullRequest
2 голосов
/ 17 февраля 2010

Я использую SQL Server 2005. Я слышал, что мы можем использовать табличную переменную вместо LEFT OUTER JOIN.

Я понимаю, что сначала мы должны поместить все значения из левой таблицы в переменную таблицы. Затем мы должны ОБНОВИТЬ переменную таблицы с правильными значениями таблицы. Затем выберите из таблицы переменную.

Кто-нибудь сталкивался с таким подходом? Не могли бы вы предложить пример в реальном времени (с запросом)?

Я не написал ни одного запроса по этому вопросу. Мой вопрос - если кто-то использовал подобный подход, я хотел бы знать сценарий и как он обрабатывается. Я понимаю, что в некоторых случаях это может быть медленнее, чем LEFT OUTER JOIN.

Пожалуйста, предположим, что мы имеем дело с таблицами, которые имеют менее 5000 записей.

Спасибо

Ответы [ 5 ]

3 голосов
/ 17 февраля 2010

Это можно сделать, , но я понятия не имею, почему вы захотите это сделать.

Это действительно кажется, что это делается задом наперед. Но если вы пытаетесь сделать это только для собственного обучения , то здесь:

DECLARE @MainTable TABLE(
        ID INT,
        Val FLOAT
)

INSERT INTO @MainTable SELECT 1, 1
INSERT INTO @MainTable SELECT 2, 2
INSERT INTO @MainTable SELECT 3, 3
INSERT INTO @MainTable SELECT 4, 4

DECLARE @LeftTable TABLE(
        ID INT,
        MainID INT,
        Val FLOAT
)

INSERT INTO @LeftTable SELECT 1, 1, 11
INSERT INTO @LeftTable SELECT 3, 3, 33

SELECT  *,
        mt.Val + ISNULL(lt.Val, 0)
FROM    @MainTable mt LEFT JOIN
        @LeftTable lt ON mt.ID = lt.MainID

DECLARE @Table TABLE(
        ID INT,
        Val FLOAT
)

INSERT INTO @Table
SELECT  ID,
        Val
FROM    @MainTable

UPDATE  @Table
SET     Val = t.Val + lt.Val
FROM    @Table t INNER JOIN
        @LeftTable lt ON t.ID = lt.ID

SELECT *
FROM    @Table
0 голосов
/ 13 декабря 2010

По моему мнению, есть одна причина сделать это: Если у вас сложный запрос с большим количеством внутренних объединений и одним левым соединением, у вас иногда возникают проблемы, потому что этот запрос в сотни раз быстрее, чем при использовании того же запроса без левого соединения.

Если вы запрашиваете много записей, в результате чего очень мало записей присоединяются к левому соединению, вы можете получить более быстрые результаты, если материализуете промежуточный результат в табличную переменную или временную таблицу.

Но обычно нет необходимости действительно обновлять данные в табличной переменной - вы можете запросить переменную таблицы, используя левое соединение, чтобы вернуть результат.

... только мои два цента.

0 голосов
/ 17 февраля 2010

Спасибо, astander.

Я попробовал с примером, приведенным ниже. Оба подхода заняли 19 секунд. Однако я полагаю, что некоторые настройки помогут подходу к обновлению таблиц быстрее, чем LEFT JOIN.

КАК Я не мастер по тюнингу, прошу вашей помощи. Любой специалист по SQL, готовый доказать это?


---- Пожалуйста, замените "" на "ниже. Я не знаком с тем, как разместить код на этом форуме ... Это вызывает некоторые проблемы ....

CREATE TABLE #MainTable ( 
        CustomerID INT  PRIMARY KEY, 
        FirstName VARCHAR(100) 
) 


DECLARE @Count INT
SET @Count = 0

DECLARE @Iterator INT
SET @Iterator = 0

WHILE @Count <8000
BEGIN

    INSERT INTO #MainTable SELECT @Count, "Cust"+CONVERT(VARCHAR(10),@Count)
    SET @Count = @Count+1

END

CREATE TABLE  #RightTable 
( 
        OrderID INT  PRIMARY KEY, 
        CustomerID INT, 
        Product VARCHAR(100) 
) 

CREATE INDEX  [IDX_CustomerID] ON #RightTable (CustomerID)

WHILE @Iterator <400000
BEGIN

        IF @Iterator % 2 = 0
        BEGIN

            INSERT INTO #RightTable  SELECT @Iterator,2, "Prod"+CONVERT(VARCHAR(10),@Iterator)
        END
        ELSE
        BEGIN
            INSERT INTO #RightTable  SELECT @Iterator,1, "Prod"+CONVERT(VARCHAR(10),@Iterator)
        END

SET @Iterator = @Iterator+1

END


-- Using LEFT JOIN

SELECT  mt.CustomerID,mt.FirstName,COUNT(rt.Product) [CountResult]
FROM    #MainTable mt 
        LEFT JOIN #RightTable rt ON mt.CustomerID = rt.CustomerID 
GROUP BY mt.CustomerID,mt.FirstName


---------------------------



-- Using Table variable Update


DECLARE @WorkingTableVariable TABLE
( 
        CustomerID INT, 
        FirstName VARCHAR(100),
        ProductCount INT  
) 

INSERT 
INTO @WorkingTableVariable (CustomerID,FirstName)
SELECT  CustomerID, FirstName FROM #MainTable 

UPDATE  @WorkingTableVariable 
SET     ProductCount = [Count]
FROM    @WorkingTableVariable wt 
        INNER JOIN
            (SELECT CustomerID,COUNT(rt.Product) AS [Count]
             FROM #RightTable rt
             GROUP BY  CustomerID) IV ON wt.CustomerID = IV.CustomerID 

SELECT CustomerID,FirstName, ISNULL(ProductCount,0) [CountResult] FROM    @WorkingTableVariable 
ORDER BY CustomerID

--------

DROP TABLE  #MainTable

DROP TABLE  #RightTable

Спасибо Lijo

0 голосов
/ 17 февраля 2010

Каждый сценарий индивидуален, и без полной информации о конкретном случае трудно сказать, будет ли это хорошим подходом для вас.

Сказав это, я бы не стал использовать подход с табличными переменными, если бы у меня не было конкретной функциональной причины - если запрос может быть выполнен с помощью стандартного запроса SELECT с использованием OUTER JOIN, то я бы использовал его как Я ожидаю, что это будет наиболее эффективным.

Времена, когда вы можете использовать вместо этого временную таблицу / переменную таблицы, больше, когда вы хотите получить промежуточный набор результатов, а затем выполнить некоторую обработку перед тем, как затем вернуть его, т. Е. Тип обработки, который не может быть сделано с прямым запросом.

Обратите внимание, что переменные таблицы очень удобны, но имейте в виду, что они не гарантированно находятся в памяти - они могут сохраняться в базе данных tempdb, как стандартные временные таблицы.

0 голосов
/ 17 февраля 2010

Не думаю, что из вашего вопроса очень ясно, чего вы хотите достичь? (Как выглядят ваши таблицы и какой результат вы хотите). Но вы, безусловно, можете выбрать данные в переменную типа таблицы и изменить ее. Это довольно удобно:

DECLARE @tbl TABLE (id INT IDENTITY(1,1), userId int, foreignId int)

INSERT INTO @tbl (userId)
    SELECT id FROM users
    WHERE name LIKE 'a%'

UPDATE @tbl t
SET
    foreignId = (SELECT id FROM foreignTable f WHERE f.userId = t.userId)

В этом примере я присвоил табличной переменной собственный столбец идентификаторов, отличный от столбца в исходной таблице. Я часто нахожу это полезным. Отрегулируйте, как вам нравится ... Опять же, не очень понятно, в чем вопрос, но я надеюсь, что это может направить вас в правильном направлении ...?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...