Медленный, но простой запрос, как сделать это быстрее? - PullRequest
0 голосов
/ 07 мая 2009

У меня есть база данных размером 6 ГБ, с множеством таблиц, но, похоже, у небольших запросов больше всего проблем, и я хочу знать, что можно сделать для их оптимизации, например, есть таблица запасов, товаров и заказов. .
Таблица Stock - это позиции на складе, в которых содержится около 100 000 записей с 25 полями, в которых хранятся ProductCode, Price и другие данные, относящиеся к акциям.
В таблице «Предметы» хранится информация об элементах, из которых более 2 000 000, а в более чем 50 полях хранятся названия элементов и другие сведения о рассматриваемом элементе или продукте.
В таблице «Заказы» хранятся «Заказы на складе», на которые был сделан заказ, плюс цена, за которую они проданы, и около 50 000 записей.

Вот запрос из этой базы данных:

SELECT Stock.SKU, Items.Name, Stock.ProductCode FROM Stock
INNER JOIN Order ON Order.OrderID = Stock.OrderID
INNER JOIN Items ON Stock.ProductCode = Items.ProductCode
WHERE (Stock.Status = 1 OR Stock.Status = 2) AND Order.Customer = 12345
ORDER BY Order.OrderDate DESC;

Учитывая приведенную здесь информацию о том, что можно сделать для улучшения этого запроса, есть и другие подобные, какие есть альтернативы. Однако природа данных и базы данных не может быть детально детализирована, поэтому, если будут даны общие приемы и методы выбора, они подойдут или что-нибудь, что обычно применяется к базам данных.
База данных - MS SQL 2000 на Windows Server 2003 с последними пакетами обновлений для каждого. Обновление БД / обновление ОС пока недоступно.


Редактировать

Индексами являются Stock.SKU, Items.ProductCode и Orders.OrderID в упомянутых таблицах.
План выполнения составляет 13-16 секунд для запроса, как это 75% времени, проведенного на складе


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


Индексы - это моя проблема, добавленная одна к внешнему ключу с заказами (клиент), и это улучшил производительность, сократив время выполнения вдвое!
Похоже, я получил туннельное зрение и сосредоточился на запросе - я работаю с БД уже пару лет, но это было очень полезно. Однако, спасибо за все примеры запросов, они являются комбинациями и функциями, которые я не рассматривал, может быть также полезным!

Ответы [ 9 ]

3 голосов
/ 07 мая 2009

Ваш код правильный ??? Я уверен, что вы что-то упустили

INNER JOIN Batch ON Order.OrderID = Orders.OrderID

и у вас есть а) в коде ...


вы всегда можете протестировать некоторые варианты с помощью инструмента плана выполнения, например

SELECT 
    s.SKU, i.Name, s.ProductCode 
FROM 
    Stock s, Orders o, Batch b, Items i
WHERE 
    b.OrderID = o.OrderID AND
    s.ProductCode = i.ProductCode AND
    s.Status IN (1, 2) AND 
    o.Customer = 12345
ORDER BY 
    o.OrderDate DESC;

и вы должны вернуть только часть, например, TOP 10 ... потребуется несколько миллисекунд, чтобы просто выбрать TOP 10, но вы сэкономите много времени, связывая его с вашим приложением.

2 голосов
/ 07 мая 2009

Вы указали индексы? На

  • Items.ProductCode
  • Stock.ProductCode
  • Orders.OrderID
  • Orders.Customer

Иногда IN может быть быстрее, чем OR, но это не так важно, как наличие индексов.

См. Ответ balexandre, ваш запрос выглядит неправильно.

2 голосов
/ 07 мая 2009

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

0 голосов
/ 07 мая 2009

Чтобы сократить мой ответ, я дал 2 часа назад (когда мои куки были отключены):

Вам нужны три индекса: клиент для таблицы Order, OrderID для запаса и ProductCode для товаров.

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

0 голосов
/ 07 мая 2009

Уточнение того, что уже сказал Кэтэлин Пити:: в вашем запросе

SELECT Stock.SKU, Items.Name, Stock.ProductCode
    FROM Stock
      INNER JOIN Order ON Order.OrderID = Stock.OrderID
      INNER JOIN Items ON Stock.ProductCode = Items.ProductCode
  WHERE (Stock.Status = 1 OR Stock.Status = 2) AND Order.Customer = 12345
  ORDER BY Order.OrderDate DESC;

критерий Order.Customer = 12345 выглядит очень конкретным, тогда как (Stock.Status = 1 ИЛИ Stock.Status = 2) звучит неопределенно. Если это правильно, эффективный запрос состоит из

1) сначала найти заказы, принадлежащие конкретному клиенту,

2) затем находим соответствующие строки Stock (с тем же OrderID), отфильтровывая строки с Status в (1, 2),

3) и, наконец, найти элементы с тем же ProductCode, что и строки Stock в 2)

Для 1) вам нужен индекс Customer для таблицы Order, для 2) индекс OrderID для таблицы Stock и 3) индекс ProductCode для таблицы Items.

Пока ваш запрос не станет намного более сложным (например, подзапросом в более крупном запросе или если акции, заказы и позиции являются только представлениями, а не таблицами), оптимизатор запросов сможет найти этот план уже из Ваш запрос. В противном случае вам придется сделать то, что предлагает kuoson (но второе предложение не поможет, если Status в (1, 2) не очень конкретен и / или Status не проиндексирован в таблице Status). Но также помните, что поддержание индексов в актуальном состоянии снижает производительность, если вы выполняете много операций вставки / обновления в таблицу.

0 голосов
/ 07 мая 2009

Не могли бы вы попробовать?

SELECT Stock.SKU, Items.Name, Stock.ProductCode FROM Stock
INNER JOIN Order ON Order.OrderID = Stock.OrderID AND (Order.Customer = 12345) AND (Stock.Status = 1 OR Stock.Status = 2))
INNER JOIN Items ON Stock.ProductCode = Items.ProductCode
ORDER BY Order.OrderDate DESC;
0 голосов
/ 07 мая 2009

Установка правильных индексов в таблицах обычно является самой большой разницей в производительности.

В Management Studio (или Query Analyzer для более ранних версий) вы можете выбрать план выполнения запроса при его запуске. В плане выполнения вы можете увидеть, что база данных действительно делает, чтобы получить результат, и какие части занимают больше всего работы. Здесь есть некоторые вещи, такие как сканирование таблиц, которые обычно являются наиболее дорогостоящей частью запроса.

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

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

0 голосов
/ 07 мая 2009

Таблица указателей, безусловно, поможет, как предложил Кэтэлин Питиș.

Другая хитрость заключается в том, чтобы уменьшить размер строк соединения либо с помощью sub select, либо для более экстремального использования временных таблиц. Например, вместо того, чтобы объединяться по всей таблице «Заказы», ​​присоединяйтесь к

(SELECT * FROM Orders WHERE Customer = 12345)

также, не присоединяйтесь напрямую к столу со складами

(SELECT * FROM Stock WHERE Status = 1 OR Status = 2)
0 голосов
/ 07 мая 2009

Некоторые общие указатели

  • Все ли поля, к которым вы присоединяетесь, проиндексированы?

  • Необходим ли заказ?

  • Как выглядит план выполнения?

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

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