Выбор последней строки (до даты) из таблицы (Sql Server 2008)

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

select top 1 x, y, z from sometable where a=b and date <= @date order by date desc

or

select x, y, z from sometable where a=b and date=(select max(date) from sometable where a=b and date <= @date)

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

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

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

Некоторое гугление обнаружило множество сравнений TOP 1 и MAX, но, как правило, для одного значения и без подзапроса. В этом случае MAX является явным победителем, но я не уверен, изменит ли это подзапрос.

Я был бы признателен за мнение тех, кто более осведомлен в этой области, чем я (которых должно быть большинство из вас!).


person philsquared    schedule 12.08.2009    source источник
comment
Я предполагаю, что первый запрос должен заканчиваться порядком по дате DESC?   -  person Mike DeFehr    schedule 12.08.2009
comment
Да, спасибо, что заметили это — теперь обновлено   -  person philsquared    schedule 12.08.2009


Ответы (2)


Ваши результаты могут различаться в зависимости от дизайна таблицы, но, вообще говоря, ТОП 1 / Порядок по технике в 2 раза лучше, когда нет индекса по дате, потому что SQL-сервер должен выполнять сканирование для каждого запроса - сначала найти максимальную дату, затем искать остальные значения на его основе. Когда есть индекс по дате (независимо от того, покрывает ли он запрос или нет), план тот же.

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

Как с точки зрения оптимальности TOP 1 в определенных обстоятельствах, так и с точки зрения того, что вы уже затронули: MAX может вернуть более 1 строки (кстати, не думайте, что когда-нибудь не вернется, если только не будет уникального индекса на сегодняшний день), я определенно предпочитаю метод TOP 1 - это метод, который я использую для всех таких запросов.

person Mike DeFehr    schedule 12.08.2009
comment
ужасно устаревшая статистика теоретически может привести к сканированию внешнего запроса в методе MAX, если оптимизатор каким-то образом обманется, думая, что он недостаточно избирательен для поиска, но я сомневаюсь в этом - в любом случае, еще одна причина использовать TOP 1 - это не попал бы в эту ловушку - person Mike DeFehr; 12.08.2009
comment
Итак, вы говорите, что TOP 1 дает все преимущества, но не недостатки - тогда как MAX может дать некоторые недостатки в некоторых обстоятельствах - но с другими вещами, как они должны быть, в нем не так много? Это имеет большой смысл. Спасибо за комментарии - person philsquared; 12.08.2009
comment
Правильно - это то, что я говорю - однако - гораздо важнее, чем то, как вы пишете запрос, какие индексы у вас есть - это определенно верно здесь и очень часто верно в других местах. Еще одна вещь, которую я подчеркну в первую очередь для других, заключается в том, что два запроса логически не эквивалентны - они будут давать одинаковые результаты только в том случае, если существует уникальный индекс по дате или максимальная дата является уникальным значением. - person Mike DeFehr; 12.08.2009
comment
В моем случае я в настоящее время не в состоянии повлиять на индексацию, но я считаю, что в большинстве случаев, которые я просматриваю, есть индекс по дате. - person philsquared; 13.08.2009
comment
Хорошо, тогда ты делаешь, что можешь. Что-нибудь еще, чтобы ответить на ваш вопрос? - person Mike DeFehr; 13.08.2009

Оптимизатор запросов имеет большую свободу и может выполнять как MAX, так и TOP 1 различными способами. То, что именно он делает, зависит, среди прочего, от исходного запроса, доступных индексов и статистики для вашей таблицы. Завтра он может выбрать другой подход, так как размер вашей таблицы или ее распределение изменятся.

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

person Andomar    schedule 12.08.2009
comment
Спасибо за ваш ответ. Я ценю преждевременную заботу об оптимизации. Частью того, что я делаю, является настройка производительности. Тот факт, что фактическая производительность может различаться, является причиной того, что я спрашиваю здесь, а не просто измеряю, т. е. меня интересует, есть ли что-то принципиально другое между подходами, которые будут мешать оптимизатору запросов, или есть ли лучший подход. Ваши комментарии предполагают, что в данном случае их, вероятно, следует рассматривать как эквивалентные...? - person philsquared; 12.08.2009
comment
Я ломаю голову, пытаясь понять, какими могут быть разные способы: если дата не проиндексирована, она будет сканировать, если дата проиндексирована, но не охватывает, она будет искать с поиском, если дата проиндексирована, и она охватывает, он будет просто искать - Какие другие подходы он может использовать? - person Mike DeFehr; 12.08.2009
comment
Например, он будет сканировать, если сочтет, что существует много строк с одинаковой датой, даже если есть индекс. - person Andomar; 12.08.2009
comment
Единственным компонентом, который может сканировать в этом сценарии, является внешний запрос MAX, но это только в том случае, если предположение об уникальных данных не выполняется или что-то не так с вашей статистикой (в любом случае у вас есть другие проблемы) - подзапрос может искать (если у него есть индекс) независимо от количества совпадающих строк, а ТОП 1 всегда будет технически сканировать (даже с уникальным индексом), но он всегда останавливается после он читает 1 - так что не совсем, нет... - person Mike DeFehr; 12.08.2009
comment
Если Sql Server считает, что будет найдено много строк, он пытается избежать поиска, связанного с поиском по индексу. Часто это правильный подход: сканирование таблицы на 100 обращений часто выполняется быстрее, чем 100 операций поиска в индексе + 100 операций поиска в таблице. Но иногда это неправильно, как в одном случае, который я видел, когда кто-то использовал подсказку индекса, чтобы сократить время выполнения с 2 часов до 2 секунд. Никогда не говори никогда :) - person Andomar; 13.08.2009
comment
Это абсолютно правильно, однако это имеет очень мало общего с этим вопросом, потому что с техникой TOP 1 сервер SQL знает, что он получает только одну строку, поэтому он идет в конец индекса, захватывает первую найденную строку, делает его поиск и завершает работу независимо от уникальности даты - возможность сканирования представлена ​​только с помощью метода MAX, что делает его неоптимальным. Вы сосредотачиваетесь на том, что если статистика сильно устарела, и предположение OP неверно, тогда могут быть альтернативные планы - не отвечает на вопрос - person Mike DeFehr; 13.08.2009
comment
Мой ответ был общим: не оптимизируйте преждевременно. Прошу прощения, что обнулился в ответ на ваши комментарии. - person Andomar; 13.08.2009