Здравствуйте, vdimas, Вы писали:
V>Бесполезно, внутри данные сначала зачитываются в массив object[], т.е. боксируются (первое копирование, причём, затратное):
V>https://github.com/dotnet/runtime/blob/main/src/libraries/System.Data.Common/src/System/Data/Common/DataRecordInternal.cs
Вы приводите другую реализацию IDataRecord. Я показал, как обойтись без боксинга/анбоксинга.
V>Причём, независимо от технологии DAL — ORM поверх DataSet, LinqToDB или EF — все они проходят через код по ссылке.
Это зависит от реализации провайдера.
Посмотрите, например, сюда:
https://referencesource.microsoft.com/#system.data/Microsoft/SqlServer/Server/SqlDataRecord.cs
V>Под капотом, в драйвере связи с БД будут готовые к использованию табличные данные, но в дотнете сделали так, что их можно лишь зачитать однонаправленно, даже если запрошен тип рекордсета снапшот, а он практически всегда именно такой, бо динамические рекордсеты признаны злейшим злом еще во второй половине 90-х.
Их можно зачитать однонаправленно и отмапить в массив клиентских объектов. Например, через linq2db.
V>В OLEDB и ODBC в похожих случаях можно рассматривать зачитанные данные как коллекцию с произвольным доступом и читать/навигироваться по данным, находящимся непосредственно в приёмном буфере драйвера (эти драйвера юзер-спейсные, ес-но, бо они лишь формируют и парсят потоки байт).
Ну, это может быть нужно только в десктопных приложениях, которые работают напрямую с базой.
Сейчас, как правило, с базой работает сервер приложений — а ему нужно быстро пробежать по данным в одну сторону, готовя ответ для клиента.
V>Собсно, DAO когда-то, хоть его и ругали за отсутствие оптимизирующего движка для сложных запросов, но в относительно простых запросах по локальной БД ему не было равных в шустрости. В т.ч. потому что приложению на его основе не требовалось копировать данные — данные читались прямо в момент обработки события WM_PAINT контрола-грида прямо из буфера драйвера.
V>На той технике и выбора-то другого не было.
А то. Видел я как-то приложение какого-то научного журнала в 1997 году. Эти орлы при показе оглавления на каждый WM_PAINT тащили XML с диска. Вот только журнал поставлялся на компакт-диске, и любой дёрг экраном занимал минуты полторы.
V>Думаю, сейчас представлений у тебя чуть больше, а я это копнул еще на первой бете дотнета, бо тогда с базами работал плотнее, чем сейчас.
V>И продолжаю уже 20 лет оставаться в недоумении, что с тех пор ничего толком не изменилось.
Ну, это как бы неправда.
V>Т.е., сильно изменилось на верхнем уровне, а на нижнем — такое же мракобесие 20-тилетней давности.
Всё ровно наоборот — нижний уровень прилично переделали, но сверху навалены тонны легаси, которые ещё переписывать и переписывать.
V>Мы это уже обсуждали.
V>Всё мн-во, скажем так, "структур" запросов в реальных приложениях конечно, кроме специализированных приложений для динамического построения произвольных запросов, которых я видел всего парочку за всю карьеру.
V>То бишь, с клиента в продуманном приложении достаточно послать ID запроса и параметры к нему.
V>И на стороне базы неплохо бы эти запросы оформить в виде сохраненных view или процедур.
Да ну неправда же. В каждом первом приложении, которое мы видим в интернете, есть кнопки "отсортировать" в заголовках колонок.
В каждом втором — кнопки "отфильтровать" в заголовках колонок.
В каждом третьем — кнопки "скрыть/показать столбцы".
Всё это — динамические запросы. Покажите мне приложение, в котором ничего этого нет.
V>А еще есть SQL-хинты, которые порой могут поднять быстродействие нагруженной базы на порядок.
Поэтому нужны не full-blown ORM типа хибернейта, а типизированные генераторы запросов типа linq2db.
S>>Пока в примерах идёт передача SQL Statement в виде тупо строки, про производительность можно вообще не заикаться.
V>А твой LinQ не строку формирует в итоге, что ле?
В итоге — строку. Вот только динамически
V>Тоже строку, только медленнее.
Теряем микросекунды, выигрываем разы.
V>Во все времена быстрее всего было вызвать хранимку в синтаксисе ODBC "{call InsertOrder(, 10, ?, ?, ?)}" c забинженными аргументами.
И это всё ещё динамическое порождение строки
V>У "красных" все планы запросов заведомо удачные, у "белых" заведомо нет, поэтому "наши" всегда побеждают. ))
V>Но ответить на простой вопрос "почему ты так решил?" уже 15-й год не можешь.
Да потому, что белым приходится брать один запрос, а потом динамически делать проекции и фильтрацию на клиенте. Ибо на 2^N вариантов запроса хранимок не напасёшся.
V>Любая локальная база предоставляет нейтивные свои драйвера/библиотеки доступа, которые самые эффективные.
V>Хотя, сервера тоже предоставляют нейтивные драйвера/библиотеки, через которую можно получить максимальные плюшки:
V>https://docs.microsoft.com/en-us/sql/relational-databases/native-client/features/sql-server-native-client-features?view=sql-server-ver15
V>Я же уже писал выше — границы абстракций DAL при таких раскладах выгодней делать чуть выше, т.е. не по OLEDB/ODBC/ADO и провайдерам/адаптерам диалектов SQL, а прямо по всему DAL.
V>Это отличается от принятой в дотнете практики.
V>С другой стороны, шаблонный код позволяет выглядеть "этому" так, будто границы абстракций проходят заметно ниже, чем есть в реальности.
V>Т.е., в любом случае трудоёмкость сравнимая, т.к. сравнимая степень переиспользования кода.
V>Просто приличная часть абстракций перетекает из runtime в compile-time, как оно принято в плюсах.
И то же самое можно делать в дотнете.
V>Обычно плюсы или джава.
Ну, то есть возвращаемся к тому, как быстро взять данные из базы и отдать их в HTTP.
V>Хотя и джавой ту джаву тоже с трудом можно назвать, чего они только не ухитряются делать, эмулируя value-типы на массивах байт.
Да, эту бы энергию да в мирных целях.
V>Т.е. не как у тебя по работе, где продаётся, скорее, инфраструктура, чем код, а просто либа с выделенной функциональностью и нехарактерными для мира дотнета техническими характеристиками.
Можно посмотреть на прайс-лист?