Помогите с SQL-запросом (Объединение представлений?) - PullRequest
0 голосов
/ 31 октября 2008

У меня есть таблица с колонками

Указатель, дата

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

Индекс, MinDate, MaxDate

, где каждый индекс указан только один раз, а MinDate (MaxDate) представляет собой самую раннюю (самую позднюю) дату во всей таблице для этого индекса . Это достаточно просто, но тогда давайте ограничим этот список, чтобы он отображался только для индексов, присутствующих в заданном диапазоне дат.

Пока у меня есть следующее:

SELECT 
    Index,
    MIN([Date]),
    MAX([Date])
FROM myTable
WHERE
    Index IN
    (SELECT Index From myTable WHERE [Date] BETWEEN '1/1/2000' AND '12/31/2000')
GROUP BY Index
ORDER BY Index ASC

Это мучительно медленно. Есть ли способ ускорить это? [Я использую SQL Server 2000.]

Спасибо!

Отредактировано: для наглядности.

Ответы [ 8 ]

4 голосов
/ 31 октября 2008

Я бы порекомендовал подход на основе производной таблицы. Как это:

SELECT 
     myTable.Index,
     MIN(myTable.[Date]),
     MAX(myTable.[Date])
FROM myTable
     Inner Join (
       SELECT Index 
       From myTable 
       WHERE [Date] BETWEEN '1/1/2000' AND '12/31/2000') As AliasName
       On myTable.Index = AliasName.Index
GROUP BY myTable.Index
ORDER BY myTable.Index ASC

РЕДАКТИРОВАТЬ: После дальнейшего просмотра, есть другой способ создать этот запрос. Следующий запрос может выполняться быстрее, медленнее или выполняться за одно и то же время. Это, конечно, зависит от того, как таблица проиндексирована.

Select [Index],
       Min([Date]),
       Max([Date])
From   myTable
Group By [Index]
Having Sum(Case When [Date] Between '1/1/2000' And '12/31/2000' Then 1 Else 0 End) > 0

В лучшем случае этот запрос заставит сканирование индекса (а не поиск) отфильтровать строки, которые вы не хотите отображать. Я рекомендую вам выполнить оба запроса и выбрать этот вариант, чтобы выполнить быстрее всего.

2 голосов
/ 31 октября 2008

Я не эксперт по SQL Server, но если вы можете делать подобранные подвыборы, это может быть быстрее.

SELECT Index,
  (SELECT MIN([Date] FROM myTable WHERE Index = m.Index),
  (SELECT MAX([Date] FROM myTable WHERE Index = m.Index)
From myTable m 
WHERE [Date] BETWEEN '1/1/2000' AND '12/31/2000'
1 голос
/ 31 октября 2008

Это должно быть сделано в двух таблицах сканирования.

SELECT
     Index,
    MIN([Date]),
    MAX([Date])
FROM myTable
WHERE
    Index IN
    (SELECT Index From myTable WHERE [Date] BETWEEN '1/1/2000' AND '12/31/2000')
GROUP BY Index
ORDER BY Index ASC
OPTION (MERGE JOIN)

Вот еще один запрос. Этот запрос получает других результатов , чем первоначально запрашивалось. При этом будут получены все индексы с диапазонами дат, которые перекрывают интересующий период (даже если в интересующем периоде для этого индекса нет фактической активности).

SELECT
    Index,
    MIN([Date]),
    MAX([Date])
FROM myTable
GROUP BY Index
HAVING MIN([Date]) < '2001-01-01' AND MAX([Date]) >= '2000-01-01')
ORDER BY Index ASC

Так что это вернется, даже если у 3 нет данных за 2000 год.

3, 1998-01-01, 2005-01-01

1 голос
/ 31 октября 2008

Джейк,

Я думаю, что вам, возможно, понадобится другой POV для этой проблемы.

Сгруппированный выбор из **Index, Min(Date), Max(Date)** не изменится радикально в течение дня по сравнению с диапазоном данных, охватываемых им (предположительно, за многие годы)

Таким образом, одним из вариантов будет создание сводной таблицы на основе данных в основной таблице ... например,

   SELECT 
       Index, 
       Min(Date) as MinDate, 
       Max(Date) as MaxDate
   INTO 
      MySummaryTable
   FROM 
      MyOriginalTable
   GROUP BY
      Index

Эта таблица может быть удалена и воссоздана на полурегулярной (ежедневной) основе с помощью задания sql. Точно так же я бы прикрепил индекс к столбцу id.

Тогда, когда вам нужно запустить ваш ежедневный запрос,

SELECT 
   summary.Index,
   summary.MinDate,
   summary.MaxDate
FROM
   MyOriginalTable mot
   INNER JOIN MySummaryTable summary
      ON mot.Index = summary.Index  --THIS IS WHERE YOUR CLUSTERED INDEX WILL PAY OFF
WHERE
   mot.Date BETWEEN '2000-01-01' AND '2000-12-31' --THIS IS WHERE A SECOND NC INDEX WILL PAY OFF
0 голосов
/ 31 октября 2008

Оператор EXISTS может быть быстрее, чем подзапрос:

SELECT
     t1.Index,
     MIN(t1.[Date]),
     MAX(t1.[Date])
FROM
     myTable t1
WHERE
     EXISTS (SELECT * FROM myTable t2 WHERE t2.Index = t1.Index AND t2.[Date] >= '1/1/2000' AND t2.[Date] < '1/1/2001')
 GROUP BY
      t1.Index

Это будет зависеть от размера таблицы и индексации, я полагаю. Мне также нравится решение G Mastros HAVING.

Еще одно важное замечание ... если ваша дата на самом деле является DATETIME, и в любой из ваших дат (сейчас или в будущем) есть временной компонент, вы можете пропустить некоторые результаты, если индекс имеет дату 12 /. 31/2000 с любым временем, кроме полуночи. Просто что-то иметь в виду. В качестве альтернативы вы можете использовать YEAR ([Date]) = 2000 (при условии, что здесь MS SQL Server). Я не знаю, была ли бы БД достаточно умной, чтобы использовать индекс по столбцу даты, если бы вы это сделали.

РЕДАКТИРОВАТЬ: добавлен GROUP BY и изменена логика даты благодаря комментарию

0 голосов
/ 31 октября 2008

Ваше объяснение не очень понятно:

, где каждый индекс указан только один раз, а MinDate (MaxDate) представляет собой самую раннюю (самую последнюю) дату, присутствующую во всей таблице.

Если это так, вы должны либо вернуть два набора результатов, либо сохранить ответ, такой как:

DECLARE @MaxDate datetime, @MinDate datetime
SELECT
    @MinDate = MIN([Date]),
    @MaxDate = MAX([Date])
FROM myTable
--
SELECT
    [Index],
    @MinDate,
    @MaxDate
FROM myTable
WHERE [Date] BETWEEN '1/1/2000' AND '12/31/2000'

Если вы хотите знать минимум / максимум для всей таблицы, а также для [Индекса], попробуйте следующее в сочетании с предыдущим кодом:

SELECT
    [Index],
    MIN([Date]) AS IndexMinDate,
    MAX([Date]) AS IndexMaxDate,
    @MinDate AS TableMinDate,
    @MaxDate AS TableMaxDate
FROM myTable
WHERE [Date] BETWEEN '1/1/2000' AND '12/31/2000'
GROUP BY [Index]
ORDER BY [Index] ASC

Также обратите внимание на индексацию столбцов, если это возможно, и план запроса. Удачи.

0 голосов
/ 31 октября 2008

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

0 голосов
/ 31 октября 2008

Вам не нужен дополнительный выбор в предложении where. Также вы можете добавить индексы в столбец даты. Сколько строк в таблице?

SELECT
    [INDEX],
    MIN ( [Date] ),
    MAX ( [Date] )
FROM
    myTable
WHERE 
    [Date] Between '1/1/2000' And '12/31/2000'
GROUP BY
    [Index]
ORDER BY
    [INDEX] ASC
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...