Здравствуйте, alex_public, Вы писали: _>Конечно.
Ок, посмотрим при случае. _>>>Хы, ты серьёзно? ))) Ты представляешь себе эффективность подобного кода? S>>Конечно представляю. _>Точно? Лично я думаю, что этот код будет в разы медленнее тупого императивного аналога. _>Тьфу, что-то я с этими разговорами про БД (где как раз актуально количество проходов) совсем заговорился и криво сформулировал свою мысль. В данном случае проблемой конечно же будет дикое количество переключений сопрограмм и ненужных копирований.
Ух ты! Резкий поворот: только что мы говорили о выразительности и объёме кода, как вдруг перешли к производительности.
Да, это правда — в дотнете с оптимизацией всё не очень хорошо. Но в этом виноват не Linq — как раз он-то делает всё, что можно, чтобы помочь оптимизатору.
Основная затычка — невозможность инлайнить делегаты, в которые превращается код на linq to objects.
Если бы были инлайны — то и копирования можно было бы устранить, т.к. результирующий выхлоп был бы эквивалентен "тупому императивному аналогу".
S>>Оптимизатор внутри промышленной СУБД умеет превращать "join c лагом" в однократное сканирование. _>Причём тут join (да ещё и с самим собой)?
При том, что это — единственный способ решить поставленную задачу на стандартном SQL без оконных функций. _>В части современных РСУБД данная проблема решается просто через функцию lag (ну или lead — опять же даже в наличие двух отдельных функций чувствуется костыльность этого решения). Так вот я крайне сомневаюсь, что её внутренняя реализация выглядит как превращение таблицы в набор пар, как в твоём примере. )))
Ох-хо-хо. В некотором смысле, бессмысленно обсуждать схожесть реализации RDBMS с тем или иным кодом на языке общего назначения.
Даже самый тупой дотнетовый код превращает выражение вроде SalesQuotaHistory.SalesQuota в разыменование указателя со смещением.
А внутри RDBMS вместо двух команд ассемблера стоит вызов подпрограмм вроде RetrieveRecordFieldValue, которые анализируют заголовок записи совместно с метаданными таблицы и прочее.
Там же интерпретатор вообще.
С другой стороны, не стоит слишком сгущать краски с "набором пар". Если мы работаем со ссылочным типом, то размер одной пары — это ровно два указателя. Сам по себе код вот этого вот PairScan вполне может быть заинлайнен, получив ровно то же самое, что и в "тупом императивном аналоге", и все эти пары будут жить только в регистрах.
_>Наверняка там простейшее прямое обращение к данным, в классическом императивном стиле. Собственно иначе и быть не может (и даже не из-за производительности), т.к. lag можно задать динамическое смещение (как и в императивном коде).
Не всё так просто. С учётом того, что исполнительный механизм работает с "перечисляемыми" источниками, которые умеют делать только GetNext() (то есть эквивалентны IEnumerator из дотнета), и не умеют GetRecordNumber(x), то скорее всего там внутри делается скользящий буфер, в случае одиночного смещения превращающийся в ту самую пару значений.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.