Это самое оптимальное решение для поиска медиан, о которых я могу думать. Имена в примере основаны на примере Джастина. Убедитесь, что индекс для таблицы
Sales.SalesOrderHeader существует со столбцами индекса CustomerId и TotalDue в этом порядке.
SELECT
sohCount.CustomerId,
AVG(sohMid.TotalDue) as TotalDueMedian
FROM
(SELECT
soh.CustomerId,
COUNT(*) as NumberOfRows
FROM
Sales.SalesOrderHeader soh
GROUP BY soh.CustomerId) As sohCount
CROSS APPLY
(Select
soh.TotalDue
FROM
Sales.SalesOrderHeader soh
WHERE soh.CustomerId = sohCount.CustomerId
ORDER BY soh.TotalDue
OFFSET sohCount.NumberOfRows / 2 - ((sohCount.NumberOfRows + 1) % 2) ROWS
FETCH NEXT 1 + ((sohCount.NumberOfRows + 1) % 2) ROWS ONLY
) As sohMid
GROUP BY sohCount.CustomerId
UPDATE
Я был немного не уверен, какой метод имеет лучшую производительность, поэтому я провел сравнение между моим методом Джастином Грантом и Джеффом Этвудсом, выполнив запрос на основе всех трех методов в одном пакете, и стоимость пакета каждого запроса составила:
без индекса:
- Шахта 30%
- Джастин Грантс 13%
- Джефф Этвудс 58%
А с индексом
- Шахта 3%.
- Джастин Грантс 10%
- Джефф Этвудс 87%
Я пытался увидеть, насколько хорошо масштабируются запросы, если у вас есть индекс, создавая больше данных из примерно 14 000 строк с коэффициентом от 2 до 512, что в итоге составляет около 7,2 миллионов строк. Обратите внимание, что я удостоверился, что поле CustomeId было уникальным для каждого раза, когда я делал одну копию, чтобы пропорция строк по сравнению с уникальным экземпляром CustomerId оставалась постоянной. В то время как я делал это, я запускал исполнения, где впоследствии перестраивал индекс, и заметил, что результаты стабилизировались примерно в 128 раз с данными, которые у меня были к этим значениям:
- Шахта 3%.
- Джастин Грантс 5%
- Джефф Этвудс 92%
Мне было интересно, как на производительность могло повлиять масштабирование числа строк, но сохранение уникального константы CustomerId, поэтому я настроил новый тест, в котором я сделал именно это. Теперь вместо стабилизации соотношение стоимости партии продолжало расходиться, также вместо примерно 20 строк на CustomerId в среднем у меня было в итоге около 10000 строк на такой уникальный Id. Числа где:
- Шахта 4%
- Джастинс 60%
- Джеффс 35%
Я убедился, что реализовал каждый метод правильно, сравнивая результаты.
Мой вывод заключается в том, что метод, который я использовал, как правило, быстрее, пока существует индекс. Также заметил, что этот метод является то, что рекомендуется для этой конкретной проблемы в этой статье https://www.microsoftpressstore.com/articles/article.aspx?p=2314819&seqNum=5
Способ еще больше повысить производительность последующих вызовов этого запроса - сохранить информацию о количестве во вспомогательной таблице. Вы могли бы даже поддерживать его, имея триггер, который обновляет и хранит информацию о количестве строк SalesOrderHeader, зависящем от CustomerId, конечно же, вы можете просто сохранить медиану.