Re[79]: MS забило на дотнет. Питону - да, сишарпу - нет?
От: Sinclair Россия https://github.com/evilguest/
Дата: 01.10.21 09:44
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Компиллируемые языки эффективнее скриптовых примерно на порядок.

V>А два порядка — это эффект уже от СМО, на этом и строился рассчёт.


S>>Даже если мы рассматриваем только pure и deterministic запросы, обеспечение ACID накладывает свои ограничения.


V>А что тут нового?

V>Там как в любом другом наборе ресурсов и очередей к ним.
А что мы считаем ресурсом? Если мы делаем классический блокировочник, то у него минимальная гранулярность блокировки — 1 строка.
То есть мы на select — запрос, который сканирует 50% таблицы с миллионом записей, последовательно захватываем и отпускаем 500000 блокировок.
На пальцах — цикл сканирования выглядит так:
foreach(var candidateRow in table.Index1.IndexSeek(predicate.IndexPart))
{
   lock(GetRowLock(candidateRow))
   {
     if(predicate.ResidualPart(candidateRow))
       yield return selector(candidateRow);
   }
}


S>>Т.е. при самом неоптимальном query plan, основные тормоза будут даже не на интерпретации выражений вроде GetIntFieldByOffset()*GetDecimalFieldByOffset(), а на захвате блокировок.


V>Эээ, тормоза на блокировках зависят от частоты конфликтов квадратично.

Даже в отсутствие конфликтов блокировки отжирают время. Вместо быстрого цикла с телом типа table[rowNumber].Slice(fieldOffset, fieldLength), которое при удаче вообще сворачивается в пару ассемблерных инструкций, у нас на каждой итерации начинается беготня по таблицам блокировок.
Интуитивно кажется, что эта беготня имеет примерно тот же порядок стоимости, что и интерпретация выражений вроде GetFieldValue(rowPointer, fieldId).
То есть мы ускорим работу не на порядок, а всего в пару раз.


V>Прикинь, уменьшение времени исполнения заявки в системе из одной машины вдвое равно масштабированию этой машины в кластер на 4 узла.

V>(это если считать, что сам кластер ничего не стоит с т.з эффективности, т.е. кластер сферический в вакууме)
Ну, вот у меня пока такое понимание, что основные задержки обработки "заявки" в современных трёхзвенках — это трипы между апп-сервером и СУБД. Если внести весь код в СУБД, то как раз получим те самые два порядка.
Компиляция — штука хорошая, но её эффект заранее трудно оценить именно потому, что не получается сделать из плана запроса код, сравнимыый с каноническим while(p*++=q*++);.

V>Походу сам с собой разговаривал. ))

Нет, почему. Я эту идею целиком поддерживаю.
V>До меня только сейчас дошло, что ты был не в курсе этих зависимостей про частоты конфликтов в СМО, т.е. банально не понимал зачем я вообще эти темы обсуждал, про компиллируемые серваки.
Ну, вот мне сначала казалось, что компиляция даст офигенный буст к производительности DBMS. А сейчас я вижу некоторые ограничения, которые на первый взгляд будут замедлять исполнение кода примерно на десятичный порядок по сравнению с компилируемым кодом, который шарашит по "голым" данным, без оглядки на isolation и durability.

В частности, от идеи работать с memory-mapped file, похоже, придётся отказаться. Потому, что write-ahead log для него потребует flush на каждое изменение, вместо одного flush на коммит.
Это сильно ухудшает производительность сканирования — вместо тупого обращения по смещению pageNo*pageSize, нужно лезть в bufferManager.getPage(pageNo), который даже на happy path добавляет лишнюю косвенность.
Поэтому MMF будут уместны только для mostly-read key-value storage, где как правило 1 транзакция == 1 изменение, а чтения доминируют над записями.

V>Ну... зато теперь ты должен лучше понимать мотивы, двигавшие меня начать обсуждения насчёт слияния бизнес-кода и функциональности сервера данных в компилябельном нейтивном оргазме. ))

Да, возможно.

V>На своей заднице испробовал когда-то, да еще на тормознутой технике конца 90-х — начала нулевых, когда любые эффекты были ну уж слишком хорошо заметны.

Вот это как раз странно. Потому что при наличии уместных индексов, уменьшение рабочего объёма в N раз сокращает время операции на константу ~ log(N).

V>Обрати внимание на мою тактику: я первым делом выясняю мотивы — что, куда, зачем, сколько это даст? Какой ценой?

V>Если дебет с кредитом даёт неплохой расклад — можно и углубиться.
Тут сложность в том же, что и в живописи: не получится сначала уловить сходство, а потом написать портрет.
И так понятно, что переход от подхода А к подходу Б даст выигрыш G с затратами L.
А вот оценить величины G и L, хотя бы с точностью до порядка — большая проблема. Ну, вот можно посмотреть в ветку с обсуждением immutable коллекций — там мелкие изменения в коде ведут в резким скачкам в производительности.
И эти изменения нифига не интуитивны — почему простой безусловный вызов по известному адресу стоит на порядок дороже, чем условный переход?
То есть "сколько это даст" можно измерить только тогда, когда уже значительная часть системы готова.
Причём рассуждать "по аналогии" нельзя. То есть, к примеру, мы можем взять какой-то кусочек кода, типа вычисления пи до 1000 знака. Запилим его на Expression<Func<int>>, прикрутим интерпретатор, и замерим скорость вычисления через интерпретатор против вычисления через сгенерированный Compile. метод. Заодно замерим скорость выполнения Compile.

Можно ли из полученных результатов делать какие-то выводы про производительность выполнения SQL кода в режиме интерпретации vs в режиме компиляции?
Нет, нельзя. Ну, то есть понятно, что медленнее от компиляции код уже не станет. А вот насколько он станет быстрее — это вопрос. Сколько будет стоить компиляция — тоже вопрос, от которого зависит ответ на более интересный вопрос "при каких условиях динамическая компиляция выиграет у интерпретации". Похожий вопрос — "при каких условиях статическая компиляция выиграет у динамической".
Вот умозрительно на эти вопросы отвечать — дохлый номер. В конце всегда рулят бенчмарки, а не рассуждения уровня "палец к носу".
А чтобы провести бенчмарки, надо что-то написать.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.