Информация об изменениях

Сообщение Re[47]: MS забило на дотнет. Питону - да, сишарпу - нет? от 03.09.2021 5:07

Изменено 03.09.2021 5:26 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>Можно посмотреть на прайс-лист?

Много тыщ в год за лицензию на каждую либу.
Прайс публично не висит, продажами занимаются сейлзы индивидуально, дать более точную инфу не могу себе позволить.
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>Можно посмотреть на прайс-лист?

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