2010-06-20 2 views
6

Это вопрос эффективности SQL.SQL-запросы - есть ли лучший способ

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

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

Комиссия выплачивается на основе ступенчатой ​​скользящей шкалы. Чем больше они продают, тем лучше комиссия. Шаги могут быть 1000, 10000, 10000 $ и так далее. Проблема реального мира сложнее, но в сущности это.

Единственный способ, которым я нашел делать это должен был сделать что-то вроде этого (очевидно, не реальный запрос)

select qty, price, salesman, 
    (select top 1 percentage from comissions 
    where comisiones.salesman = saleslines.salesman 
    and saleslines.qty > comisiones.qty 
    order by comissiones.qty desc 
) percentage 
from saleslines 

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

Есть ли лучший способ сделать это? Я не ищу, чтобы кто-то переписывал мой sql, более «смотрю как запросы foobar», и я могу взять его оттуда.

Структура реальной жизни может быть указана для разных продавцов, статей и клиентов и даже даты продаж. Он также меняется время от времени, поэтому все должно управляться данными в таблицах ... iee Я не могу установить фиксированные диапазоны в sql. Текущий запрос возвращает около 3-400000 строк и занимает около 20-30 секунд. К счастью, он используется только ежемесячно, но медленность меня раздражает.

Это на mssql.

Ян

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

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

Это может лучше захватить его

select client-code, product, product-family, qty, price, discount, salesman, 
    (select top 1 percentage from comissions 
     where comisiones.salesman = saleslines.salesman 
     and saleslines.qty > comisiones.qty 
     and [ 
      a collection of conditions which may or may not apply: 
      Exclude rows if the salesman has offered discounts above max discounts 
       which appear in each row in the commissions table 
      There may be a special scale for the product family 
      There may be a special scale for the product 
      There may be a special scale for the client 

      A few more cases 
      ] 
     order by [ 
      The user can control the order though a table 
      which can prioritize by client, family or product 
      It normally goes from most to least specific. 
      ] 
    ) percentage 
    from saleslines 

Излишне говорить реальный запрос не легко следовать. Просто чтобы сделать жизнь более интересной, ее именование - это многоязычный.

Таким образом, для каждого ряда торговых линий комиссия может быть разной.

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

Во всем вышеперечисленном я исключаю специальные предложения по срокам.

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

+0

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

+0

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

+0

Какую версию SQL Server вы используете? –

ответ

3

Если вы используете версию SQL Server, который поддерживает общую таблицу выражения, такие как SQL Server 2005 и более поздних версии, более эффективное решение может быть:

With RankedCommissions As 
    (
    Select SL.qty, SL.price, SL.salesman, C.percentage 
     , Row_Number() Over (Partition By SL.salesman Order By C.Qty Desc) As CommissionRank 
    From SalesLines As SL 
     Join Commissions As C 
      On SL.salesman = C.salesman 
       And SL.qty > C.qty 
    ) 
Select qtr, price, salesman, percentage 
From RankedCommissions 
Where CommissionRank = 1 

Если вам необходимо учитывать возможность того, что нет комиссий значения для данного продавца, где SalesLine.Qty> Commission.Qty, то вы могли бы сделать что-то вроде:

With RankedCommissions As 
    (
    Select SL.qty, SL.price, SL.salesman, C.percentage 
     , Row_Number() Over (Partition By SL.salesman Order By C.Qty Desc) As CommissionRank 
    From SalesLines As SL 
     Join Commissions As C 
      On SL.salesman = C.salesman 
       And SL.qty > C.qty 
    ) 
Select SL.qtr, SL.price, SL.salesman, RC.percentage 
From SalesLines As SL 
    Left Join RankedCommissions As RC 
     On RC.salesman = SL.salesman 
      And RC.CommissionRank = 1 
+0

Вы не нуждаетесь в поддержке выражений common-table для использования этого подхода. Вы можете так же легко написать CTE как встроенное представление. Однако функция 'ROW_NUMBER' требует SQL Server 2005 или выше. –

+0

Мой первоначальный запрос был написан для sql2000, но db недавно перешел на sql2008, что и вызвало мой интерес к использованию новых функций. Томас, похоже, это решение. Однако это совсем другой подход, поэтому мне придется некоторое время сидеть сложа руки и видеть, как я могу его использовать. Как решение. Спасибо -Ian – Ian

+0

@Ian - Поймите. CTE и функции ранжирования, такие как Row_Number, являются невероятно мощной новой функцией в 2005/2008 году. Они помогают упростить ряд проблемных запросов, таких как тот, который вы представили. Реальный трюк в моем решении - это использование предложения Partition By, которое заказывает значения продавцом (продавцом?). – Thomas

0
select 
    qty, price, salesman, 
    max(percentage) 
from saleslines 
    inner join comissions on commisions.salesman = saleslines.salesman and 
      saleslines.qty > comissions.qty 
group by 
    qty, price, salesman 
+0

-1, ваш код дает самый высокий процент; в исходном запросе указывается процент для максимального количества. – Gabe

+0

INNER JOIN имеет условие (saleslines.qty> comissions.qty), которое отфильтровывает все линии связи с количеством, большим, чем количественная сумма продаж. Максимальное количество оставшихся строк дает процент за наибольшее количество (не самый высокий процент). – potatopeelings

+0

или так я думаю :-) – potatopeelings

Смежные вопросы