Когда использовать CTE для инкапсуляции промежуточных результатов, а когда разрешить СУБД беспокоиться о массовых объединениях - PullRequest
0 голосов
/ 31 декабря 2010

Это вопрос теории SQL.Я могу привести пример, но я не думаю, что это необходимо, чтобы высказать свою точку зрения.Любой, кто имеет опыт работы с SQL, сразу поймет, о чем я говорю.

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

У меня есть база данных, в которой имеется 3 или 4 таких объединения.Это превращает то, что будет несколько записей во множество.Меня беспокоит то, что таблицы будут большими в производстве, поэтому количество этих соединенных строк будет огромным.Кроме того, тяжелая математика выполняется в каждом ряду, и идея выполнения математики в дублирующих рядах достаточна, чтобы заставить любого вздрогнуть.

У меня есть два вопроса.Во-первых, это то, о чем я должен заботиться, или SQL Server будет разумно понимать, что все эти строки являются дубликатами, и соответственно оптимизировать всю обработку?

Во-вторых, есть ли преимущество в группировке каждой части запросачтобы получить только отдельные значения, входящие в следующую часть запроса, используя что-то вроде:

WITH t1 AS (
  SELECT DISTINCT... [or GROUP BY]

),
t2 AS (
  SELECT DISTINCT...

),
t3 AS (
  SELECT DISTINCT...

)
SELECT...

Я часто видел применение DISTINCT для подзапросов.Очевидно, есть причина для этого.Тем не менее, я говорю о чем-то немного другом и, возможно, более тонком и хитром.

Ответы [ 2 ]

1 голос
/ 31 декабря 2010

Вы говорите о таком запросе?

В плане видно, что SQL Server выполняет вычисления для небольшого числа строк перед объединением, а не для большого количества записей после объединения.

CREATE TABLE #BigTable
(
n INT PRIMARY KEY
);


WITH E00(N) AS (SELECT 1 UNION ALL SELECT 1),   --2
        E02(N) AS (SELECT 1 FROM E00 a, E00 b), --4
        E04(N) AS (SELECT 1 FROM E02 a, E02 b), --16
        E08(N) AS (SELECT 1 FROM E04 a, E04 b), --256
        E16(N) AS (SELECT 1 FROM E08 a, E08 b)  --65,536
INSERT INTO #BigTable
SELECT TOP 10000 ROW_NUMBER() OVER (ORDER BY (SELECT 0))
FROM E16        


CREATE TABLE #SmallTable
(
n INT PRIMARY KEY
);

insert into #SmallTable select top 20 * from #BigTable ORDER BY n

SELECT SIN(COS(LOG(#SmallTable.n))) 
FROM #SmallTable join #BigTable on #BigTable.n > #SmallTable.n

Plan

0 голосов
/ 31 декабря 2010

Я не совсем уверен в этом вопросе, если честно ...

Нет никакой разницы между CTE и производной таблицей.CTE - это просто макрос.

WITH 
  t1 AS (SELECT DISTINCT... [or GROUP BY]),
  t2 AS (SELECT DISTINCT...)
SELECT * FROM t1 JOIN t2 ON ...

- это то же самое, что и

SELECT
   *
FROM
   (SELECT DISTINCT... [or GROUP BY]) t1
   JOIN
   (SELECT DISTINCT...) t2 ON ...

. При возникновении проблем может возникнуть ассоциативность таблиц

FROM
  t1
  LEFT JOIN
  t2 ON t1. = t2.
  JOIN
  t3 ON t2. = t3.

может отличатьсяна

FROM
  t1
  LEFT JOIN
  (
  SELECT *
  FROM
     t2
    JOIN
     t3 ON t2. = t3.
  ) Td ON t1. = Td.

Однако, если вам нужны DISTINCT в строке, то это может быть «почему вы используете EXISTS» или «почему у вас есть декартовы объединения»

...