Нужна помощь в улучшении производительности этого SQL-запроса - PullRequest
1 голос
/ 16 августа 2011

Я не очень большой эксперт по TSSQL. У нас есть запрос, который возвращает почти 2 миллиона записей. Для запуска требуется более 2,5 минут. Мы добавили индексы, и это сократилось на одну минуту (раньше на это уходило 3,5 минуты), но 2,5 минуты все еще слишком медленно. Может кто-нибудь показать мне, как изменить этот запрос, чтобы улучшить его производительность? Я подозреваю, что изменение должно произойти с оператором «in» и с тем, как рассчитывается значение «LOCATION», но я не уверен, как это сделать.

select distinct
A.ptid,
A.ptmgrx,
A.ptmgry,
A.fename,
B.fename XFENAME,
A.rt1 route,
A.pr,
A.mp,
A.rdbranch,
A.gs grade,
A.cs,
A.csmp,
A.cspath,
(select distinct twpname from tamc.dbo.fipsmdot where fipscode = A.fmcdl) + '; ' +
(select distinct county from tamc.dbo.fipsmdot where fipsco = A.countyl) + ' County, ' +
(select distinct twpname from tamc.dbo.fipsmdot where fipscode = A.fmcdr) + '; ' +
(select distinct county from tamc.dbo.fipsmdot where fipsco = A.countyr) + ' County' LOCATION
from intersectionApproaches A INNER JOIN intersectionApproaches B ON A.ptid = B.ptid
where A.ptid in 
(select distinct C.ptid from intersectionApproaches C, intersectionApproaches B
where C.ptid = B.ptid)

Изменения: Сервер БД - это MS SQL Server 2008. У меня есть план выполнения, но, кажется, нет способа сделать его видимым. Сохраняется в виде файла .sqlplan. Не уверен, что это будет работать для кого-то еще. Но я могу предоставить некоторую информацию от него.

29% времени тратится на различную сортировку.

15% времени тратится на создание "катушки индекса" (это происходит три раза)

6% затрачивается на «настольную катушку» (только один раз)

8% делают "Сортировку"

Чтобы ответить JNK: Исходный запрос находился в хранимой процедуре и принимал несколько параметров, которые ограничивали набор результатов. Вот оригинальный запрос с этими параметрами:

select distinct
A.ptid,
A.ptmgrx,
A.ptmgry,
A.fename,
B.fename XFENAME,
A.rt1 route,
A.pr,
A.mp,
A.rdbranch,
A.gs grade,
A.cs,
A.csmp,
A.cspath,
(select distinct twpname from tamc.dbo.fipsmdot where fipscode = A.fmcdl) + '; ' +
(select distinct county from tamc.dbo.fipsmdot where fipsco = A.countyl) + ' County, ' +
(select distinct twpname from tamc.dbo.fipsmdot where fipscode = A.fmcdr) + '; ' +
(select distinct county from tamc.dbo.fipsmdot where fipsco = A.countyr) + ' County' LOCATION
from intersectionApproaches A INNER JOIN intersectionApproaches B ON A.ptid = B.ptid
where A.ptid in 
(select distinct C.ptid from intersectionApproaches C, intersectionApproaches B
where C.ptid = B.ptid
and (C.fename + isnull(' ' + C.fetype,'') like @str + '%' or @str in (C.rt1name, C.rt2name, C.rt3name)) and (B.fename + isnull(' ' + B.fetype,'') like @xstr + '%' or @xstr in (B.rt1name, B.rt2name, B.rt3name)))

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

Подробнее Редактирование: Таблица «Перекрестные подходы» - это таблица подходов к перекрестку. Например, стандартное пересечение дорог состоит из 4 подъездов (по одному на каждую сторону пересечения, с которой движение может приблизиться к перекрестку). Первоначальная цель хранимой процедуры состояла в том, чтобы вернуть список подходов пересечения, соответствующих определенной паре названий улиц.

Например, у вас есть "Main" и "1st", и у них есть пересечение.

Существует четыре подхода пересечения для этого пересечения.

"Главный и 1-й"

"1-й и главный"

"1-й и 1-й"

«Главное и главное»

Все они имеют один и тот же PTID, который является ID пересечения.

Однако в таблице IntersectionApproaches есть только одно поле для названия улицы "FENAME". Чтобы завершить запись, нам нужно название соответствующего перекрестка (отсюда и «B.Fename XFENAME» в запросе). Это позволяет нам запросить результат и сказать «достань мне все записи с улицей« Мэйн »и перекрестком с« 1-й »». Кроме того, нам также необходимо заполнить значение «LOCATION», как это определено несколькими операторами «выбрать разные» в запросе, потому что мы можем фильтровать и это.

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

Надеюсь, это поможет ...

Ответы [ 3 ]

5 голосов
/ 16 августа 2011

Я считаю шесть вхождений DISTINCT в вашем коде.Это слишком много.

Даже не видя ваших данных, DISTINCT в предложении IN в конце совершенно не требуется.IN не волнует, есть ли у вас дубликаты или нет в подзапросе, так как он замыкается.

Похоже, все ваши подзапросы могут быть заменены на JOIN.

Прямо сейчас вы запрашиваете fipsmdot пять раз за строку из своей основной таблицы.

У вас также есть то, что кажется совершенно ненужным INNER JOIN дляглавная таблица (самостоятельное объединение).

Чтобы получить более подробную информацию, вам необходимо опубликовать пример данных, структуру таблицы и то, к чему вы стремитесь.

3 голосов
/ 16 августа 2011

Три Четыре вещи выпрыгивают:

  • Странное использование IN. Это может быть упрощено, потому что A.ptid = B.ptid = C.ptid
  • Подзапросов в строке: изменить на JOIN
  • Почему ПРИСОЕДИНЯЙТЕСЬ к пересечению, Подходит дважды на ключ? Это заставляет ненужный внешний DISTINCT
  • (спасибо Биллу) БЕССИЛЬНО ГДЕ

Попробуйте это исправить, чтобы устранить некоторые проблемы

select distinct
  A.ptid,
  A.ptmgrx,
  A.ptmgry,
  A.fename,
  B.fename XFENAME,
  A.rt1 route,
  A.pr,
  A.mp,
  A.rdbranch,
  A.gs grade,
  A.cs,
  A.csmp,
  A.cspath,
  a1.twpname '; ' +
  a2.twpname + ' County, ' +
  a3.twpname  + '; ' +
  a4.twpname  + ' County' LOCATION
from
  intersectionApproaches A
  INNER JOIN
  intersectionApproaches B ON A.ptid = B.ptid
  JOIN
  (select distinct twpname from tamc.dbo.fipsmdot) a1 ON a1.fipscode = A.fmcdl
  JOIN
  (select distinct twpname from tamc.dbo.fipsmdot) a2 ON a2.fipsco = A.countyl
  JOIN
  (select distinct twpname from tamc.dbo.fipsmdot) a3 ON a3.fipscode = A.fmcdr
  JOIN
  (select distinct twpname from tamc.dbo.fipsmdot) a4 ON a4.fipsco = A.countyr
/*
 not needed as Bill said. Always true
where
  EXISTS (SELECT *
      FROM intersectionApproaches C
      WHERE C.ptid = A.ptid)
*/
0 голосов
/ 17 августа 2011

Я публикую это здесь в качестве ответа, чтобы другие, кто смотрит в будущее, увидели это при необходимости.

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

Вот новый запрос:

    select 
DISTINCT
A.ptid,
  A.ptmgrx,
  A.ptmgry,
  A.fename,
  B.fename XFENAME,
  A.rt1 route,
  A.pr,
  A.mp,
  A.rdbranch,
  A.gs grade,
  A.cs,
  A.csmp,
  A.cspath,
  c1.twpname  + '; ' +
  c2.county + ' County, ' +
  c3.twpname + '; ' +
  c4.county + ' County' LOCATION,
  A.rt1name,
  A.rt2name,
  A.rt3name,
  A.fetype,
  B.rt1name AS Xrt1name,
  B.rt2name AS Xrt2name,
  B.rt3name AS Xrt3name,
  B.fetype AS Xfetype
  from dbo.intersectionApproaches A 
  INNER JOIN intersectionApproaches B ON A.ptid = B.ptid
  JOIN
  (select distinct twpname, fipscode from tamc.dbo.fipsmdot) c1 ON c1.fipscode = A.fmcdl
  JOIN
  (select distinct county, fipsco from tamc.dbo.fipsmdot) c2 ON c2.fipsco = A.countyl
    JOIN
  (select distinct twpname, fipscode from tamc.dbo.fipsmdot) c3 ON c3.fipscode = A.fmcdr
  JOIN
  (select distinct county, fipsco from tamc.dbo.fipsmdot) c4 ON c4.fipsco = A.countyr

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

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

...