Сообщение Re[47]: MS забило на дотнет. Питону - да, сишарпу - нет? от 03.09.2021 5:07
Изменено 03.09.2021 7:59 vdimas
Re[47]: MS забило на дотнет. Питону - да, сишарпу - нет?
Здравствуйте, Sinclair, Вы писали:
V>>Бесполезно, внутри данные сначала зачитываются в массив object[], т.е. боксируются (первое копирование, причём, затратное):
V>>https://github.com/dotnet/runtime/blob/main/src/libraries/System.Data.Common/src/System/Data/Common/DataRecordInternal.cs
S>Вы приводите другую реализацию IDataRecord. Я показал, как обойтись без боксинга/анбоксинга.
Я привожу что есть по факту.
А то, что у тебя — это надо самим делать обертку поверх ODBC и там малость не так тривиально, но это уже подробности.
V>>Причём, независимо от технологии DAL — ORM поверх DataSet, LinqToDB или EF — все они проходят через код по ссылке.
S>Это зависит от реализации провайдера.
S>Посмотрите, например, сюда: https://referencesource.microsoft.com/#system.data/Microsoft/SqlServer/Server/SqlDataRecord.cs
Не ту ссылку дал, надо смотреть сюда:
https://referencesource.microsoft.com/#system.data/fx/src/data/Microsoft/SqlServer/Server/MemoryRecordBuffer.cs,17
Путь данных еще более извилист и всё-равно данные еще дважды копируются.
V>>Под капотом, в драйвере связи с БД будут готовые к использованию табличные данные, но в дотнете сделали так, что их можно лишь зачитать однонаправленно, даже если запрошен тип рекордсета снапшот, а он практически всегда именно такой, бо динамические рекордсеты признаны злейшим злом еще во второй половине 90-х.
S>Их можно зачитать однонаправленно и отмапить в массив клиентских объектов. Например, через linq2db.
Можно.
Через миллион телодвижений унутре.
linq2db — это самая вершинка айберга, пока данные до него дойдут — сто раз вспотеют.
V>>В OLEDB и ODBC в похожих случаях можно рассматривать зачитанные данные как коллекцию с произвольным доступом и читать/навигироваться по данным, находящимся непосредственно в приёмном буфере драйвера (эти драйвера юзер-спейсные, ес-но, бо они лишь формируют и парсят потоки байт).
S>Ну, это может быть нужно только в десктопных приложениях, которые работают напрямую с базой.
А чем рендеринг в HTML/JSON принципиально отличается от рендеринга куда-то еще?
S>Сейчас, как правило, с базой работает сервер приложений — а ему нужно быстро пробежать по данным в одну сторону, готовя ответ для клиента.
ОК, пусть даже в одну сторону.
Я всё-равно не понимаю, зачем унутре реализации в дотнете создают копии данных для каждой строки.
Выглядит как собачий бред, сорри.
Я бы даже не додумался так делать.
Просто плотно занимаюсь в т.ч. парсингом протоколов и организацией доступа к данным, приходящим по сетке.
Так вот, не придумано еще ничего быстрее чем разметить входной поток (он в любом случае парсится), а наружу отдавать данные согласно разметке.
Грубо, для каждого поля подготавливается акцессор.
Будут его потом дёргать или нет — дело клиента.
В дотнете эта стадия тоже происходит, только данные еще зачитываются в создаваемое по new хранилище для каждого поля.
А потом уже происходит чтение из этого хранилища.
Индюшатина-с...
S>А то. Видел я как-то приложение какого-то научного журнала в 1997 году. Эти орлы при показе оглавления на каждый WM_PAINT тащили XML с диска. Вот только журнал поставлялся на компакт-диске, и любой дёрг экраном занимал минуты полторы.
Еще не разучился приводить двоечников в пример?
V>>Думаю, сейчас представлений у тебя чуть больше, а я это копнул еще на первой бете дотнета, бо тогда с базами работал плотнее, чем сейчас.
V>>И продолжаю уже 20 лет оставаться в недоумении, что с тех пор ничего толком не изменилось.
S>Ну, это как бы неправда.
V>>Т.е., сильно изменилось на верхнем уровне, а на нижнем — такое же мракобесие 20-тилетней давности.
S>Всё ровно наоборот — нижний уровень прилично переделали, но сверху навалены тонны легаси, которые ещё переписывать и переписывать.
Сорри, но ты сейчас малость из пальца насасываешь.
Оно примерно так и было, как есть сейчас.
Разве что написали дотнетный драйвер к MS SQL, изначально это была обычная обёртка над OLEDB, как и для остального ADO.Net.
Но это было сделано еще с выходом 2-го дотнета.
Да и сам OLEDB драйвер к MS SQL когда-то был оберткой над ODBC-кодом их же драйвера, пока не написали родной для OLEDB.
V>>То бишь, с клиента в продуманном приложении достаточно послать ID запроса и параметры к нему.
V>>И на стороне базы неплохо бы эти запросы оформить в виде сохраненных view или процедур.
S>Да ну неправда же. В каждом первом приложении, которое мы видим в интернете, есть кнопки "отсортировать" в заголовках колонок.
Не аргумент.
Таких отображений в этом "первом приложении" (которое магазин какой-нить) аж одно на каждую группу товаров.
S>В каждом втором — кнопки "отфильтровать" в заголовках колонок.
Попадает в мой случай.
S>В каждом третьем — кнопки "скрыть/показать столбцы".
Где скрыть их можно на любом уровне, особенно если речь шла о клиенте.
Т.е. на уровне запроса к БД, на уровне сервера приложений, прямо на клиенте.
Вряд ли в клиентском приложении при сокрытии или отображении колонок будет заново делаться запрос к базе.
S>Всё это — динамические запросы.
Ну вот смотри, я понаставил кучу флажков:
https://www.wildberries.ru/catalog/elektronika/telefony-i-gadzhety/mobilnye-telefony?sort=newly&cardsize=c246x328&page=1&f10466=3722640%3B514814%3B3725238%3B3725535%3B18630%3B18632%3B18640%3B441183%3B3199823&f90746=214513%3B142905%3B140423%3B140427%3B140428%3B172656%3B172657&f75438=3698872%3B3698698%3B3749957%3B130329%3B3698382%3B174305%3B81543%3B81534%3B121020
Флажки булевские, т.е. кодируются битами.
Покажи, где ты здесь увидел динамический запрос?
Не, я примерно понимаю, на что ты намекал, на длиннющие условия навроде:
OR WorkTime=T133 OR WorkTime=T160 OR ...
И так по всем группам условий, не только по WorkTime...
И не говори, что ты на это не намекал, потому что только такое представление требует динамического построения. ))
А стоит взять битовый вектор, и запрос динамически строить не придётся — просто подаётся требуемая маска как аргумент.
На стороне базы маска займёт столько integer-полей, сколько требуется.
Допустим, аж пару BigInt, итого у нас комбинаторика по колву масок:
0 0
0 1
1 0
1 1
Всего 4 запроса.
Или два — 0 0 и 1 1, т.е., если есть хоть один бит — формируем маску целиком.
S>Покажите мне приложение, в котором ничего этого нет.
Показал.
Оно всё-равно не доказывает твои утверждения.
Просто показывает твои странные представления о кодировании данных.
V>>А еще есть SQL-хинты, которые порой могут поднять быстродействие нагруженной базы на порядок.
S>Поэтому нужны не full-blown ORM типа хибернейта, а типизированные генераторы запросов типа linq2db.
Но хинты уникальны для различных провайдеров.
Это почему DAL стоит затачивать под конкретного провайдера, а не под абстрактного, бо различные базы уникальны в своих фичах.
S>>>Пока в примерах идёт передача SQL Statement в виде тупо строки, про производительность можно вообще не заикаться.
V>>А твой LinQ не строку формирует в итоге, что ле?
S>В итоге — строку. Вот только динамически
И с чего ты решил, что это быстрее, даже если бы в некоей другой технологии тоже формировали такую же ужасную строку?
Судя по интонации подаваемого тобой — "просто нравится".
V>>Тоже строку, только медленнее.
S>Теряем микросекунды, выигрываем разы.
Если строки запросов те же — ничего не выигрываешь.
Опять выдаёшь желаемое за действительное, бо "просто нравится". (С)
В общем, я еще на прошлой итерации заподозрил, что ты сольёшься в привычную демагогию.
На деле, при адекватном проектировании будет в разы быстрее, конечно.
V>>Во все времена быстрее всего было вызвать хранимку в синтаксисе ODBC "{call InsertOrder(, 10, ?, ?, ?)}" c забинженными аргументами.
S>И это всё ещё динамическое порождение строки
Такую строку обычно не требуется порождать динамически, она обычно константа.
Тут важнее не забыть включить разогрев, коль есть аргументы и ожидается серия вызовов потом с разными аргументами.
V>>У "красных" все планы запросов заведомо удачные, у "белых" заведомо нет, поэтому "наши" всегда побеждают. ))
V>>Но ответить на простой вопрос "почему ты так решил?" уже 15-й год не можешь.
S>Да потому, что белым приходится брать один запрос, а потом динамически делать проекции и фильтрацию на клиенте.
Откуда у тебя "один запрос"?
Можно цитату?
S>Ибо на 2^N вариантов запроса хранимок не напасёшся.
И что помешало тебе самостоятельно пройти дисциплину "теория кодирования информации"?
Там несложно.
Как ты при проектировании борешься с избыточностью, не понимая самого этого понятия?
Блин, 2^N запросов ))
(на моей памяти минимум дважды в разные годы тебя поправляли по теме кодирования информации, надо было заполниь пробел после первого же раза)
V>>Т.е., в любом случае трудоёмкость сравнимая, т.к. сравнимая степень переиспользования кода.
V>>Просто приличная часть абстракций перетекает из runtime в compile-time, как оно принято в плюсах.
S>И то же самое можно делать в дотнете.
А смысл, если для получения одного значения int одного поля будут десятки виртуальных вызовов и пара промежуточных копирований?
В этих условиях какая фик разница, где абстракции нарезаны?
В этом хаосе брёвна превращаются в спички, на которых никто не экономит.
V>>Обычно плюсы или джава.
S>Ну, то есть возвращаемся к тому, как быстро взять данные из базы и отдать их в HTTP.
V>>Хотя и джавой ту джаву тоже с трудом можно назвать, чего они только не ухитряются делать, эмулируя value-типы на массивах байт.
S>Да, эту бы энергию да в мирных целях.
Как у тебя всё просто...
Если в джавовских программах доходит до эмуляции value-типов массивами байт, то можешь примерно представить степень вылизанности остального.
Хотя, всё-равно нубство, их LMAX Disruptor сосёт рядом с нашими решениями.
Я хорошо в курсе, что в дотнете так вылизывать пока мест не принято, к счастью.
И даже высмеивается.
Но чем громче высмеивается, тем нам лучше.
V>>Т.е. не как у тебя по работе, где продаётся, скорее, инфраструктура, чем код, а просто либа с выделенной функциональностью и нехарактерными для мира дотнета техническими характеристиками.
S>Можно посмотреть на прайс-лист?
Много тыщ в год за лицензию на каждую либу.
Прайс публично не висит, продажами занимаются сейлзы индивидуально, дать более точную инфу не могу себе позволить.
V>>Бесполезно, внутри данные сначала зачитываются в массив object[], т.е. боксируются (первое копирование, причём, затратное):
V>>https://github.com/dotnet/runtime/blob/main/src/libraries/System.Data.Common/src/System/Data/Common/DataRecordInternal.cs
S>Вы приводите другую реализацию IDataRecord. Я показал, как обойтись без боксинга/анбоксинга.
Я привожу что есть по факту.
А то, что у тебя — это надо самим делать обертку поверх ODBC и там малость не так тривиально, но это уже подробности.
V>>Причём, независимо от технологии DAL — ORM поверх DataSet, LinqToDB или EF — все они проходят через код по ссылке.
S>Это зависит от реализации провайдера.
S>Посмотрите, например, сюда: https://referencesource.microsoft.com/#system.data/Microsoft/SqlServer/Server/SqlDataRecord.cs
Не ту ссылку дал, надо смотреть сюда:
https://referencesource.microsoft.com/#system.data/fx/src/data/Microsoft/SqlServer/Server/MemoryRecordBuffer.cs,17
Путь данных еще более извилист и всё-равно данные еще дважды копируются.
V>>Под капотом, в драйвере связи с БД будут готовые к использованию табличные данные, но в дотнете сделали так, что их можно лишь зачитать однонаправленно, даже если запрошен тип рекордсета снапшот, а он практически всегда именно такой, бо динамические рекордсеты признаны злейшим злом еще во второй половине 90-х.
S>Их можно зачитать однонаправленно и отмапить в массив клиентских объектов. Например, через linq2db.
Можно.
Через миллион телодвижений унутре.
linq2db — это самая вершинка айберга, пока данные до него дойдут — сто раз вспотеют.
V>>В OLEDB и ODBC в похожих случаях можно рассматривать зачитанные данные как коллекцию с произвольным доступом и читать/навигироваться по данным, находящимся непосредственно в приёмном буфере драйвера (эти драйвера юзер-спейсные, ес-но, бо они лишь формируют и парсят потоки байт).
S>Ну, это может быть нужно только в десктопных приложениях, которые работают напрямую с базой.
А чем рендеринг в HTML/JSON принципиально отличается от рендеринга куда-то еще?
S>Сейчас, как правило, с базой работает сервер приложений — а ему нужно быстро пробежать по данным в одну сторону, готовя ответ для клиента.
ОК, пусть даже в одну сторону.
Я всё-равно не понимаю, зачем унутре реализации в дотнете создают копии данных для каждой строки.
Выглядит как собачий бред, сорри.
Я бы даже не додумался так делать.
Просто плотно занимаюсь в т.ч. парсингом протоколов и организацией доступа к данным, приходящим по сетке.
Так вот, не придумано еще ничего быстрее чем разметить входной поток (он в любом случае парсится), а наружу отдавать данные согласно разметке.
Грубо, для каждого поля подготавливается акцессор.
Будут его потом дёргать или нет — дело клиента.
В дотнете эта стадия тоже происходит, только данные еще зачитываются в создаваемое по new хранилище для каждого поля.
А потом уже происходит чтение из этого хранилища.
Индюшатина-с...
S>А то. Видел я как-то приложение какого-то научного журнала в 1997 году. Эти орлы при показе оглавления на каждый WM_PAINT тащили XML с диска. Вот только журнал поставлялся на компакт-диске, и любой дёрг экраном занимал минуты полторы.
Еще не разучился приводить двоечников в пример?
V>>Думаю, сейчас представлений у тебя чуть больше, а я это копнул еще на первой бете дотнета, бо тогда с базами работал плотнее, чем сейчас.
V>>И продолжаю уже 20 лет оставаться в недоумении, что с тех пор ничего толком не изменилось.
S>Ну, это как бы неправда.
V>>Т.е., сильно изменилось на верхнем уровне, а на нижнем — такое же мракобесие 20-тилетней давности.
S>Всё ровно наоборот — нижний уровень прилично переделали, но сверху навалены тонны легаси, которые ещё переписывать и переписывать.
Сорри, но ты сейчас малость из пальца насасываешь.
Оно примерно так и было, как есть сейчас.
Разве что написали дотнетный драйвер к MS SQL, изначально это была обычная обёртка над OLEDB, как и для остального ADO.Net.
Но это было сделано еще с выходом 2-го дотнета.
Да и сам OLEDB драйвер к MS SQL когда-то был оберткой над ODBC-кодом их же драйвера, пока не написали родной для OLEDB.
V>>То бишь, с клиента в продуманном приложении достаточно послать ID запроса и параметры к нему.
V>>И на стороне базы неплохо бы эти запросы оформить в виде сохраненных view или процедур.
S>Да ну неправда же. В каждом первом приложении, которое мы видим в интернете, есть кнопки "отсортировать" в заголовках колонок.
Не аргумент.
Таких отображений в этом "первом приложении" (которое магазин какой-нить) аж одно на каждую группу товаров.
S>В каждом втором — кнопки "отфильтровать" в заголовках колонок.
Попадает в мой случай.
S>В каждом третьем — кнопки "скрыть/показать столбцы".
Где скрыть их можно на любом уровне, особенно если речь шла о клиенте.
Т.е. на уровне запроса к БД, на уровне сервера приложений, прямо на клиенте.
Вряд ли в клиентском приложении при сокрытии или отображении колонок будет заново делаться запрос к базе.
S>Всё это — динамические запросы.
Ну вот смотри, я понаставил кучу флажков:
https://www.wildberries.ru/catalog/elektronika/telefony-i-gadzhety/mobilnye-telefony?sort=newly&cardsize=c246x328&page=1&f10466=3722640%3B514814%3B3725238%3B3725535%3B18630%3B18632%3B18640%3B441183%3B3199823&f90746=214513%3B142905%3B140423%3B140427%3B140428%3B172656%3B172657&f75438=3698872%3B3698698%3B3749957%3B130329%3B3698382%3B174305%3B81543%3B81534%3B121020
Флажки булевские, т.е. кодируются битами.
Покажи, где ты здесь увидел динамический запрос?
Не, я примерно понимаю, на что ты намекал, на длиннющие условия навроде:
OR WorkTime=T133 OR WorkTime=T160 OR ...
И так по всем группам условий, не только по WorkTime...
И не говори, что ты на это не намекал, потому что только такое представление требует динамического построения. ))
А стоит взять битовый вектор, и запрос динамически строить не придётся — просто подаётся требуемая маска как аргумент.
На стороне базы маска займёт столько integer-полей, сколько требуется.
Допустим, аж пару BigInt, итого у нас комбинаторика по колву масок:
0 0
0 1
1 0
1 1
Всего 4 запроса.
Или два — 0 0 и 1 1, т.е., если есть хоть один бит — формируем маску целиком.
S>Покажите мне приложение, в котором ничего этого нет.
Показал.
Оно всё-равно не доказывает твои утверждения.
Просто показывает твои странные представления о кодировании данных.
V>>А еще есть SQL-хинты, которые порой могут поднять быстродействие нагруженной базы на порядок.
S>Поэтому нужны не full-blown ORM типа хибернейта, а типизированные генераторы запросов типа linq2db.
Но хинты уникальны для различных провайдеров.
Это почему DAL стоит затачивать под конкретного провайдера, а не под абстрактного, бо различные базы уникальны в своих фичах.
S>>>Пока в примерах идёт передача SQL Statement в виде тупо строки, про производительность можно вообще не заикаться.
V>>А твой LinQ не строку формирует в итоге, что ле?
S>В итоге — строку. Вот только динамически
И с чего ты решил, что это быстрее, даже если бы в некоей другой технологии тоже формировали такую же ужасную строку?
Судя по интонации подаваемого тобой — "просто нравится".
V>>Тоже строку, только медленнее.
S>Теряем микросекунды, выигрываем разы.
Если строки запросов те же — ничего не выигрываешь.
Опять выдаёшь желаемое за действительное, бо "просто нравится". (С)
В общем, я еще на прошлой итерации заподозрил, что ты сольёшься в привычную демагогию.
На деле, при адекватном проектировании будет в разы быстрее, конечно.
V>>Во все времена быстрее всего было вызвать хранимку в синтаксисе ODBC "{call InsertOrder(, 10, ?, ?, ?)}" c забинженными аргументами.
S>И это всё ещё динамическое порождение строки
Такую строку обычно не требуется порождать динамически, она обычно константа.
Тут важнее не забыть включить разогрев, коль есть аргументы и ожидается серия вызовов потом с разными аргументами.
V>>У "красных" все планы запросов заведомо удачные, у "белых" заведомо нет, поэтому "наши" всегда побеждают. ))
V>>Но ответить на простой вопрос "почему ты так решил?" уже 15-й год не можешь.
S>Да потому, что белым приходится брать один запрос, а потом динамически делать проекции и фильтрацию на клиенте.
Откуда у тебя "один запрос"?
Можно цитату?
S>Ибо на 2^N вариантов запроса хранимок не напасёшся.
И что помешало тебе самостоятельно пройти дисциплину "теория кодирования информации"?
Там несложно.
Как ты при проектировании борешься с избыточностью, не понимая самого этого понятия?
Блин, 2^N запросов ))
(на моей памяти минимум дважды в разные годы тебя поправляли по теме кодирования информации, надо было заполниь пробел после первого же раза)
V>>Т.е., в любом случае трудоёмкость сравнимая, т.к. сравнимая степень переиспользования кода.
V>>Просто приличная часть абстракций перетекает из runtime в compile-time, как оно принято в плюсах.
S>И то же самое можно делать в дотнете.
А смысл, если для получения одного значения int одного поля будут десятки виртуальных вызовов и пара промежуточных копирований?
В этих условиях какая фик разница, где абстракции нарезаны?
В этом хаосе брёвна превращаются в спички, на которых никто не экономит.
V>>Обычно плюсы или джава.
S>Ну, то есть возвращаемся к тому, как быстро взять данные из базы и отдать их в HTTP.
V>>Хотя и джавой ту джаву тоже с трудом можно назвать, чего они только не ухитряются делать, эмулируя value-типы на массивах байт.
S>Да, эту бы энергию да в мирных целях.
Как у тебя всё просто...
Если в джавовских программах доходит до эмуляции value-типов массивами байт, то можешь примерно представить степень вылизанности остального.
Хотя, всё-равно нубство, их LMAX Disruptor сосёт рядом с нашими решениями.
Я хорошо в курсе, что в дотнете так вылизывать пока мест не принято, к счастью.
И даже высмеивается.
Но чем громче высмеивается, тем нам лучше.
V>>Т.е. не как у тебя по работе, где продаётся, скорее, инфраструктура, чем код, а просто либа с выделенной функциональностью и нехарактерными для мира дотнета техническими характеристиками.
S>Можно посмотреть на прайс-лист?
Много тыщ в год за лицензию на каждую либу.
Прайс публично не висит, продажами занимаются сейлзы индивидуально, дать более точную инфу не могу себе позволить.
Re[47]: MS забило на дотнет. Питону - да, сишарпу - нет?
Здравствуйте, Sinclair, Вы писали:
V>>Бесполезно, внутри данные сначала зачитываются в массив object[], т.е. боксируются (первое копирование, причём, затратное):
V>>https://github.com/dotnet/runtime/blob/main/src/libraries/System.Data.Common/src/System/Data/Common/DataRecordInternal.cs
S>Вы приводите другую реализацию IDataRecord. Я показал, как обойтись без боксинга/анбоксинга.
Я привожу что есть по факту.
А то, что у тебя — это надо самим делать обертку поверх ODBC и там малость не так тривиально, но это уже подробности.
V>>Причём, независимо от технологии DAL — ORM поверх DataSet, LinqToDB или EF — все они проходят через код по ссылке.
S>Это зависит от реализации провайдера.
S>Посмотрите, например, сюда: https://referencesource.microsoft.com/#system.data/Microsoft/SqlServer/Server/SqlDataRecord.cs
Не ту ссылку дал, надо смотреть сюда:
https://referencesource.microsoft.com/#system.data/fx/src/data/Microsoft/SqlServer/Server/MemoryRecordBuffer.cs,17
Путь данных еще более извилист и всё-равно данные еще дважды копируются.
И в любом случае твой пример только для MSSQL, а для любых других баз на основе OLEDB или ODBC будет как я дал ссылку на исходники дотнета.
V>>Под капотом, в драйвере связи с БД будут готовые к использованию табличные данные, но в дотнете сделали так, что их можно лишь зачитать однонаправленно, даже если запрошен тип рекордсета снапшот, а он практически всегда именно такой, бо динамические рекордсеты признаны злейшим злом еще во второй половине 90-х.
S>Их можно зачитать однонаправленно и отмапить в массив клиентских объектов. Например, через linq2db.
Можно.
Через миллион телодвижений унутре.
linq2db — это самая вершинка айберга, пока данные до него дойдут — сто раз вспотеют.
V>>В OLEDB и ODBC в похожих случаях можно рассматривать зачитанные данные как коллекцию с произвольным доступом и читать/навигироваться по данным, находящимся непосредственно в приёмном буфере драйвера (эти драйвера юзер-спейсные, ес-но, бо они лишь формируют и парсят потоки байт).
S>Ну, это может быть нужно только в десктопных приложениях, которые работают напрямую с базой.
А чем рендеринг в HTML/JSON принципиально отличается от рендеринга куда-то еще?
S>Сейчас, как правило, с базой работает сервер приложений — а ему нужно быстро пробежать по данным в одну сторону, готовя ответ для клиента.
ОК, пусть даже в одну сторону.
Я всё-равно не понимаю, зачем унутре реализации в дотнете создают копии данных для каждой строки.
Выглядит как собачий бред, сорри.
Я бы даже не додумался так делать.
Просто плотно занимаюсь в т.ч. парсингом протоколов и организацией доступа к данным, приходящим по сетке.
Так вот, не придумано еще ничего быстрее чем разметить входной поток (он в любом случае парсится), а наружу отдавать данные согласно разметке.
Грубо, для каждого поля подготавливается акцессор.
Будут его потом дёргать или нет — дело клиента.
В дотнете эта стадия тоже происходит, только данные еще зачитываются в создаваемое по new хранилище для каждого поля.
А потом уже происходит чтение из этого хранилища.
Индюшатина-с...
S>А то. Видел я как-то приложение какого-то научного журнала в 1997 году. Эти орлы при показе оглавления на каждый WM_PAINT тащили XML с диска. Вот только журнал поставлялся на компакт-диске, и любой дёрг экраном занимал минуты полторы.
Еще не разучился приводить двоечников в пример?
V>>Думаю, сейчас представлений у тебя чуть больше, а я это копнул еще на первой бете дотнета, бо тогда с базами работал плотнее, чем сейчас.
V>>И продолжаю уже 20 лет оставаться в недоумении, что с тех пор ничего толком не изменилось.
S>Ну, это как бы неправда.
V>>Т.е., сильно изменилось на верхнем уровне, а на нижнем — такое же мракобесие 20-тилетней давности.
S>Всё ровно наоборот — нижний уровень прилично переделали, но сверху навалены тонны легаси, которые ещё переписывать и переписывать.
Сорри, но ты сейчас малость из пальца насасываешь.
Оно примерно так и было, как есть сейчас.
Разве что написали дотнетный драйвер к MS SQL, изначально это была обычная обёртка над OLEDB, как и для остального ADO.Net.
Но это было сделано еще с выходом 2-го дотнета.
Да и сам OLEDB драйвер к MS SQL когда-то был оберткой над ODBC-кодом их же драйвера, пока не написали родной для OLEDB.
V>>То бишь, с клиента в продуманном приложении достаточно послать ID запроса и параметры к нему.
V>>И на стороне базы неплохо бы эти запросы оформить в виде сохраненных view или процедур.
S>Да ну неправда же. В каждом первом приложении, которое мы видим в интернете, есть кнопки "отсортировать" в заголовках колонок.
Не аргумент.
Таких отображений в этом "первом приложении" (которое магазин какой-нить) аж одно на каждую группу товаров.
S>В каждом втором — кнопки "отфильтровать" в заголовках колонок.
Попадает в мой случай.
S>В каждом третьем — кнопки "скрыть/показать столбцы".
Где скрыть их можно на любом уровне, особенно если речь шла о клиенте.
Т.е. на уровне запроса к БД, на уровне сервера приложений, прямо на клиенте.
Вряд ли в клиентском приложении при сокрытии или отображении колонок будет заново делаться запрос к базе.
S>Всё это — динамические запросы.
Ну вот смотри, я понаставил кучу флажков:
https://www.wildberries.ru/catalog/elektronika/telefony-i-gadzhety/mobilnye-telefony?sort=newly&cardsize=c246x328&page=1&f10466=3722640%3B514814%3B3725238%3B3725535%3B18630%3B18632%3B18640%3B441183%3B3199823&f90746=214513%3B142905%3B140423%3B140427%3B140428%3B172656%3B172657&f75438=3698872%3B3698698%3B3749957%3B130329%3B3698382%3B174305%3B81543%3B81534%3B121020
Флажки булевские, т.е. кодируются битами.
Покажи, где ты здесь увидел динамический запрос?
Не, я примерно понимаю, на что ты намекал, на длиннющие условия навроде:
OR WorkTime=T133 OR WorkTime=T160 OR ...
И так по всем группам условий, не только по WorkTime...
И не говори, что ты на это не намекал, потому что только такое представление требует динамического построения. ))
А стоит взять битовый вектор, и запрос динамически строить не придётся — просто подаётся требуемая маска как аргумент.
На стороне базы маска займёт столько integer-полей, сколько требуется.
Допустим, аж пару BigInt, итого у нас комбинаторика по колву масок:
0 0
0 1
1 0
1 1
Всего 4 запроса.
Или два — 0 0 и 1 1, т.е., если есть хоть один бит — формируем маску целиком.
S>Покажите мне приложение, в котором ничего этого нет.
Показал.
Оно всё-равно не доказывает твои утверждения.
Просто показывает твои странные представления о кодировании данных.
V>>А еще есть SQL-хинты, которые порой могут поднять быстродействие нагруженной базы на порядок.
S>Поэтому нужны не full-blown ORM типа хибернейта, а типизированные генераторы запросов типа linq2db.
Но хинты уникальны для различных провайдеров.
Это почему DAL стоит затачивать под конкретного провайдера, а не под абстрактного, бо различные базы уникальны в своих фичах.
S>>>Пока в примерах идёт передача SQL Statement в виде тупо строки, про производительность можно вообще не заикаться.
V>>А твой LinQ не строку формирует в итоге, что ле?
S>В итоге — строку. Вот только динамически
И с чего ты решил, что это быстрее, даже если бы в некоей другой технологии тоже формировали такую же ужасную строку?
Судя по интонации подаваемого тобой — "просто нравится".
V>>Тоже строку, только медленнее.
S>Теряем микросекунды, выигрываем разы.
Если строки запросов те же — ничего не выигрываешь.
Опять выдаёшь желаемое за действительное, бо "просто нравится". (С)
В общем, я еще на прошлой итерации заподозрил, что ты сольёшься в привычную демагогию.
На деле, при адекватном проектировании будет в разы быстрее, конечно.
V>>Во все времена быстрее всего было вызвать хранимку в синтаксисе ODBC "{call InsertOrder(, 10, ?, ?, ?)}" c забинженными аргументами.
S>И это всё ещё динамическое порождение строки
Такую строку обычно не требуется порождать динамически, она обычно константа.
Тут важнее не забыть включить разогрев, коль есть аргументы и ожидается серия вызовов потом с разными аргументами.
V>>У "красных" все планы запросов заведомо удачные, у "белых" заведомо нет, поэтому "наши" всегда побеждают. ))
V>>Но ответить на простой вопрос "почему ты так решил?" уже 15-й год не можешь.
S>Да потому, что белым приходится брать один запрос, а потом динамически делать проекции и фильтрацию на клиенте.
Откуда у тебя "один запрос"?
Можно цитату?
S>Ибо на 2^N вариантов запроса хранимок не напасёшся.
И что помешало тебе самостоятельно пройти дисциплину "теория кодирования информации"?
Там несложно.
Как ты при проектировании борешься с избыточностью, не понимая самого этого понятия?
Блин, 2^N запросов ))
(на моей памяти минимум дважды в разные годы тебя поправляли по теме кодирования информации, надо было заполниь пробел после первого же раза)
V>>Т.е., в любом случае трудоёмкость сравнимая, т.к. сравнимая степень переиспользования кода.
V>>Просто приличная часть абстракций перетекает из runtime в compile-time, как оно принято в плюсах.
S>И то же самое можно делать в дотнете.
А смысл, если для получения одного значения int одного поля будут десятки виртуальных вызовов и пара промежуточных копирований?
В этих условиях какая фик разница, где абстракции нарезаны?
В этом хаосе брёвна превращаются в спички, на которых никто не экономит.
V>>Обычно плюсы или джава.
S>Ну, то есть возвращаемся к тому, как быстро взять данные из базы и отдать их в HTTP.
V>>Хотя и джавой ту джаву тоже с трудом можно назвать, чего они только не ухитряются делать, эмулируя value-типы на массивах байт.
S>Да, эту бы энергию да в мирных целях.
Как у тебя всё просто...
Если в джавовских программах доходит до эмуляции value-типов массивами байт, то можешь примерно представить степень вылизанности остального.
Хотя, всё-равно нубство, их LMAX Disruptor сосёт рядом с нашими решениями.
Я хорошо в курсе, что в дотнете так вылизывать пока мест не принято, к счастью.
И даже высмеивается.
Но чем громче высмеивается, тем нам лучше.
V>>Т.е. не как у тебя по работе, где продаётся, скорее, инфраструктура, чем код, а просто либа с выделенной функциональностью и нехарактерными для мира дотнета техническими характеристиками.
S>Можно посмотреть на прайс-лист?
Много тыщ в год за лицензию на каждую либу.
Прайс публично не висит, продажами занимаются сейлзы индивидуально, дать более точную инфу не могу себе позволить.
V>>Бесполезно, внутри данные сначала зачитываются в массив object[], т.е. боксируются (первое копирование, причём, затратное):
V>>https://github.com/dotnet/runtime/blob/main/src/libraries/System.Data.Common/src/System/Data/Common/DataRecordInternal.cs
S>Вы приводите другую реализацию IDataRecord. Я показал, как обойтись без боксинга/анбоксинга.
Я привожу что есть по факту.
А то, что у тебя — это надо самим делать обертку поверх ODBC и там малость не так тривиально, но это уже подробности.
V>>Причём, независимо от технологии DAL — ORM поверх DataSet, LinqToDB или EF — все они проходят через код по ссылке.
S>Это зависит от реализации провайдера.
S>Посмотрите, например, сюда: https://referencesource.microsoft.com/#system.data/Microsoft/SqlServer/Server/SqlDataRecord.cs
Не ту ссылку дал, надо смотреть сюда:
https://referencesource.microsoft.com/#system.data/fx/src/data/Microsoft/SqlServer/Server/MemoryRecordBuffer.cs,17
Путь данных еще более извилист и всё-равно данные еще дважды копируются.
И в любом случае твой пример только для MSSQL, а для любых других баз на основе OLEDB или ODBC будет как я дал ссылку на исходники дотнета.
V>>Под капотом, в драйвере связи с БД будут готовые к использованию табличные данные, но в дотнете сделали так, что их можно лишь зачитать однонаправленно, даже если запрошен тип рекордсета снапшот, а он практически всегда именно такой, бо динамические рекордсеты признаны злейшим злом еще во второй половине 90-х.
S>Их можно зачитать однонаправленно и отмапить в массив клиентских объектов. Например, через linq2db.
Можно.
Через миллион телодвижений унутре.
linq2db — это самая вершинка айберга, пока данные до него дойдут — сто раз вспотеют.
V>>В OLEDB и ODBC в похожих случаях можно рассматривать зачитанные данные как коллекцию с произвольным доступом и читать/навигироваться по данным, находящимся непосредственно в приёмном буфере драйвера (эти драйвера юзер-спейсные, ес-но, бо они лишь формируют и парсят потоки байт).
S>Ну, это может быть нужно только в десктопных приложениях, которые работают напрямую с базой.
А чем рендеринг в HTML/JSON принципиально отличается от рендеринга куда-то еще?
S>Сейчас, как правило, с базой работает сервер приложений — а ему нужно быстро пробежать по данным в одну сторону, готовя ответ для клиента.
ОК, пусть даже в одну сторону.
Я всё-равно не понимаю, зачем унутре реализации в дотнете создают копии данных для каждой строки.
Выглядит как собачий бред, сорри.
Я бы даже не додумался так делать.
Просто плотно занимаюсь в т.ч. парсингом протоколов и организацией доступа к данным, приходящим по сетке.
Так вот, не придумано еще ничего быстрее чем разметить входной поток (он в любом случае парсится), а наружу отдавать данные согласно разметке.
Грубо, для каждого поля подготавливается акцессор.
Будут его потом дёргать или нет — дело клиента.
В дотнете эта стадия тоже происходит, только данные еще зачитываются в создаваемое по new хранилище для каждого поля.
А потом уже происходит чтение из этого хранилища.
Индюшатина-с...
S>А то. Видел я как-то приложение какого-то научного журнала в 1997 году. Эти орлы при показе оглавления на каждый WM_PAINT тащили XML с диска. Вот только журнал поставлялся на компакт-диске, и любой дёрг экраном занимал минуты полторы.
Еще не разучился приводить двоечников в пример?
V>>Думаю, сейчас представлений у тебя чуть больше, а я это копнул еще на первой бете дотнета, бо тогда с базами работал плотнее, чем сейчас.
V>>И продолжаю уже 20 лет оставаться в недоумении, что с тех пор ничего толком не изменилось.
S>Ну, это как бы неправда.
V>>Т.е., сильно изменилось на верхнем уровне, а на нижнем — такое же мракобесие 20-тилетней давности.
S>Всё ровно наоборот — нижний уровень прилично переделали, но сверху навалены тонны легаси, которые ещё переписывать и переписывать.
Сорри, но ты сейчас малость из пальца насасываешь.
Оно примерно так и было, как есть сейчас.
Разве что написали дотнетный драйвер к MS SQL, изначально это была обычная обёртка над OLEDB, как и для остального ADO.Net.
Но это было сделано еще с выходом 2-го дотнета.
Да и сам OLEDB драйвер к MS SQL когда-то был оберткой над ODBC-кодом их же драйвера, пока не написали родной для OLEDB.
V>>То бишь, с клиента в продуманном приложении достаточно послать ID запроса и параметры к нему.
V>>И на стороне базы неплохо бы эти запросы оформить в виде сохраненных view или процедур.
S>Да ну неправда же. В каждом первом приложении, которое мы видим в интернете, есть кнопки "отсортировать" в заголовках колонок.
Не аргумент.
Таких отображений в этом "первом приложении" (которое магазин какой-нить) аж одно на каждую группу товаров.
S>В каждом втором — кнопки "отфильтровать" в заголовках колонок.
Попадает в мой случай.
S>В каждом третьем — кнопки "скрыть/показать столбцы".
Где скрыть их можно на любом уровне, особенно если речь шла о клиенте.
Т.е. на уровне запроса к БД, на уровне сервера приложений, прямо на клиенте.
Вряд ли в клиентском приложении при сокрытии или отображении колонок будет заново делаться запрос к базе.
S>Всё это — динамические запросы.
Ну вот смотри, я понаставил кучу флажков:
https://www.wildberries.ru/catalog/elektronika/telefony-i-gadzhety/mobilnye-telefony?sort=newly&cardsize=c246x328&page=1&f10466=3722640%3B514814%3B3725238%3B3725535%3B18630%3B18632%3B18640%3B441183%3B3199823&f90746=214513%3B142905%3B140423%3B140427%3B140428%3B172656%3B172657&f75438=3698872%3B3698698%3B3749957%3B130329%3B3698382%3B174305%3B81543%3B81534%3B121020
Флажки булевские, т.е. кодируются битами.
Покажи, где ты здесь увидел динамический запрос?
Не, я примерно понимаю, на что ты намекал, на длиннющие условия навроде:
OR WorkTime=T133 OR WorkTime=T160 OR ...
И так по всем группам условий, не только по WorkTime...
И не говори, что ты на это не намекал, потому что только такое представление требует динамического построения. ))
А стоит взять битовый вектор, и запрос динамически строить не придётся — просто подаётся требуемая маска как аргумент.
На стороне базы маска займёт столько integer-полей, сколько требуется.
Допустим, аж пару BigInt, итого у нас комбинаторика по колву масок:
0 0
0 1
1 0
1 1
Всего 4 запроса.
Или два — 0 0 и 1 1, т.е., если есть хоть один бит — формируем маску целиком.
S>Покажите мне приложение, в котором ничего этого нет.
Показал.
Оно всё-равно не доказывает твои утверждения.
Просто показывает твои странные представления о кодировании данных.
V>>А еще есть SQL-хинты, которые порой могут поднять быстродействие нагруженной базы на порядок.
S>Поэтому нужны не full-blown ORM типа хибернейта, а типизированные генераторы запросов типа linq2db.
Но хинты уникальны для различных провайдеров.
Это почему DAL стоит затачивать под конкретного провайдера, а не под абстрактного, бо различные базы уникальны в своих фичах.
S>>>Пока в примерах идёт передача SQL Statement в виде тупо строки, про производительность можно вообще не заикаться.
V>>А твой LinQ не строку формирует в итоге, что ле?
S>В итоге — строку. Вот только динамически
И с чего ты решил, что это быстрее, даже если бы в некоей другой технологии тоже формировали такую же ужасную строку?
Судя по интонации подаваемого тобой — "просто нравится".
V>>Тоже строку, только медленнее.
S>Теряем микросекунды, выигрываем разы.
Если строки запросов те же — ничего не выигрываешь.
Опять выдаёшь желаемое за действительное, бо "просто нравится". (С)
В общем, я еще на прошлой итерации заподозрил, что ты сольёшься в привычную демагогию.
На деле, при адекватном проектировании будет в разы быстрее, конечно.
V>>Во все времена быстрее всего было вызвать хранимку в синтаксисе ODBC "{call InsertOrder(, 10, ?, ?, ?)}" c забинженными аргументами.
S>И это всё ещё динамическое порождение строки
Такую строку обычно не требуется порождать динамически, она обычно константа.
Тут важнее не забыть включить разогрев, коль есть аргументы и ожидается серия вызовов потом с разными аргументами.
V>>У "красных" все планы запросов заведомо удачные, у "белых" заведомо нет, поэтому "наши" всегда побеждают. ))
V>>Но ответить на простой вопрос "почему ты так решил?" уже 15-й год не можешь.
S>Да потому, что белым приходится брать один запрос, а потом динамически делать проекции и фильтрацию на клиенте.
Откуда у тебя "один запрос"?
Можно цитату?
S>Ибо на 2^N вариантов запроса хранимок не напасёшся.
И что помешало тебе самостоятельно пройти дисциплину "теория кодирования информации"?
Там несложно.
Как ты при проектировании борешься с избыточностью, не понимая самого этого понятия?
Блин, 2^N запросов ))
(на моей памяти минимум дважды в разные годы тебя поправляли по теме кодирования информации, надо было заполниь пробел после первого же раза)
V>>Т.е., в любом случае трудоёмкость сравнимая, т.к. сравнимая степень переиспользования кода.
V>>Просто приличная часть абстракций перетекает из runtime в compile-time, как оно принято в плюсах.
S>И то же самое можно делать в дотнете.
А смысл, если для получения одного значения int одного поля будут десятки виртуальных вызовов и пара промежуточных копирований?
В этих условиях какая фик разница, где абстракции нарезаны?
В этом хаосе брёвна превращаются в спички, на которых никто не экономит.
V>>Обычно плюсы или джава.
S>Ну, то есть возвращаемся к тому, как быстро взять данные из базы и отдать их в HTTP.
V>>Хотя и джавой ту джаву тоже с трудом можно назвать, чего они только не ухитряются делать, эмулируя value-типы на массивах байт.
S>Да, эту бы энергию да в мирных целях.
Как у тебя всё просто...
Если в джавовских программах доходит до эмуляции value-типов массивами байт, то можешь примерно представить степень вылизанности остального.
Хотя, всё-равно нубство, их LMAX Disruptor сосёт рядом с нашими решениями.
Я хорошо в курсе, что в дотнете так вылизывать пока мест не принято, к счастью.
И даже высмеивается.
Но чем громче высмеивается, тем нам лучше.
V>>Т.е. не как у тебя по работе, где продаётся, скорее, инфраструктура, чем код, а просто либа с выделенной функциональностью и нехарактерными для мира дотнета техническими характеристиками.
S>Можно посмотреть на прайс-лист?
Много тыщ в год за лицензию на каждую либу.
Прайс публично не висит, продажами занимаются сейлзы индивидуально, дать более точную инфу не могу себе позволить.