Pull to refresh
3
0
Евгений Кочуров @evkochurov

Руководитель отдела разработки

Send message
-- JSONB
UPDATE entity_jsonb
SET properties = jsonb_set(properties, '{"color"}', '"blue"')
WHERE id = 120;

Надо иметь ввиду, что значение в колонке properties заменяется целиком. Теперь представим, что JSON-ы, которые мы храним, достаточно большие. И если типичная нагрузка — это частые обновления отдельно взятых полей JSON-а, то EAV может оказаться и на голову эффективнее.

В общем, в статье незаслуженно обойден вопрос о производительности записи и влиянии на WAL.
Я тоже поначалу отнесся скептически, но потом сходил по ссылке на оригинал. Там не столько про REST на примере oracle, сколько про node-oracledb на примере REST. И мне показалось, что эта серия статей — неплохая вводная к документации. Во всяком случае, хотя уже давно с node-oracledb работаю, углядел в статьях пару фишек, которые прошли мимо меня при чтении документации.
Ну можно перебором, наверняка есть что-то умное

Да даже без умного, совсем по-простому можно: https://jsbin.com/cozakeyude/1/edit?js,console
И еще: даже в отсортированном списке поиск по-прежнему линейный. Потому что если вы на любом шаге поиска можете прыгнуть сразу в желаемое место, то это уже не список, а какая-то другая структура данных. Например, дерево или массив. Но там вставка элемента в середину — отнюдь не такая тривиальная операция, как в списке.
Вы не учитываете, что это надо делать на каждом шаге, т.е. время не logN, а N*logN.
Оверкилл, говорите? Ваше решение будет медленнее и не лучше по расходу памяти, чем у DrPass — ему нужно получить разрешение иметь всего один бит в каждом элементе списка под свои нужды (позволят ли это условия задачи — другой вопрос), а вам — целый указатель в отдельной структуре, которую надо еще поддерживать в отсортированном виде и в которой совершать поиск на каждом шаге обхода списка.
1. Кому-то сложная, кому-то нет. Решать ее можно по-разному и ход мысли в процессе решения позволит что-то узнать о способностях кандидата. Но я согласен с автором — решение этой задачи мало что покажет об уровне владения языком, если это не С/С++.
2. Тут вы и по времени, и по дополнительной памяти имеете линейную сложность, а в статье время линейное, а доп.память — константа. Так что новую статью, наверное, нет смысла делать.

То, что вы придумали — это еще хороший алгоритм. Кандидат запросто может предложить линейную память и квадратичное время: хранить список указателей на пройденные вершины и на каждом шаге проверять текущую вершину на вхождение в список.
Как работает µWebSockets не скажу, не пробовал его. А в стандартных стримах повторная отправка не нужна. Если write() вернул false, отправку рекомендуют приостанавливать до события drain. Но даже если проигнорировать рекомендацию и продолжить слать данные — они в конце концов будут отправлены, ничего не потеряется. Правда, в этом случае nodejs начнет кушать память под буферизацию и памяти может в итоге не хватить…

Поэтому я люблю метод pipe() у стримов — если возникает backpressure во writable стриме, pipe() автоматически поставит на паузу readable стрим до события drain. Т.е. с pipe() в норме буферы не могут съесть памяти больше некоторой константы.
Правда, это полностью верно только для стандартных стримов. Если самому создать класс с интерфейсом Readable Stream и не позаботиться, чтобы у него pipe() работал корректно, то на жор памяти нарваться очень легко.
В стандартных стримах ноды нужно дожидаться события drain nodejs.org/api/stream.html#stream_event_drain. Здесь, если я правильно понимаю, для той же цели есть unetworking.github.io/uWebSockets.js/generated/interfaces/websocketbehavior.html#drain
Чтобы гарантировать правильность сколько-нибудь сложной программы, ее нужно писать одновременно с доказательством. Доказать _уже_ написанную (без оглядки на способ доказательства) программу на языке общего назначения (скажем, Java), как правило, нереально.
async function parallel(m){return await Promise.all(m)};

А какой смысл в этой функции? Скрыть из кода упоминание Promise? Но асинхронная функция всегда возвращает обещание, поэтому было бы достаточно написать так:
function parallel(m){return Promise.all(m)};

Эффект тот же, но работать будет быстрее, так как не создает совершенно лишнее по смыслу обещание-обертку, которое разрешается после разрешения обещания Promise.all(). Проверял только на NodeJS v8.11.3, возможно, когда-нибудь оптимизатор и такие вещи научится упрощать.

Но на мой взгляд, гораздо лучше вызывать Promise.all() напрямую, без оберток. В любом сколько-нибудь реальном применении async/await все равно придется разбираться с обещаниями, так что скрывать их из кода нет смысла.
Например, как-то искал модуль для nodejs, реализующий файловое хранилище в локальной файловой системе. Функция была на тот момент второстепенной для проекта, надо было уметь «всего лишь» сохранять и извлекать файлы по id, поэтому не хотелось тащить монстров типа Jackrabbit. Все, что нашел, было или заброшено, или сыро, или годно только на совсем игрушечные объемы данных.
В итоге хранилище весьма шустро «завелосипедили». Всё отлично, всё работает. Но со временем в системе появлялось все больше модулей, которые используют хранилище для своих нужд, соответственно, требования к его функциональности возросли. Самые неприятные, с точки зрения усилий по реализации, касались конкурентного доступа к файлам и задач текущего обслуживания хранилища.

Очень похоже, что интеграция со специализированным хранилищем обошлась бы дешевле велосипеда. Собственно, в чем тут архитектурный просчет: на тот момент в используемом стеке технологий на стороне сервера приложений была только nodejs, и хотелось обойтись без добавления всяких tomcat'ов только ради «второстепенной» задачи. Стремились как раз таки сэкономить. Просчет не смертельный, но все же просчет.
Если готовое решение не поддерживается, не особо развивается и не особо известно, то его скорее всего вообще лучше обойти стороной.

Не раз сталкивался с тем, что если все найденные готовые решения вот такие, то это значит, что я, как и авторы этих решений, где-то просчитался в архитектуре.
Думаю, русские математики часто пишут не хуже… только почему-то мало подобного можно прочесть в оригинале на русском. Обидно.


На эту тему Непейвода интересно в свое время писал.

nepejvoda-n-n.livejournal.com/tag/%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%20%D0%A7%D0%B5%D0%B9%D1%82%D0%B8%D0%BD%D0%B0
Достаточно запоминать последнее успешное завершение запроса в серии однотипных запросов, чтобы суметь проигнорировать «опоздавшие» результаты:
jsfiddle.net/fvau6s51/13
Обновления самой Ноды изредка ломают обратную совместимость (в основном, отрубанием устаревших функций, для которых значительное время существует альтернатива), но это обычно легко отслеживается и правится, когда речь идет только о js-коде.

А вот API для подключения расширений к Ноде на других языках несколько раз кардинально менялось. И если использовать модуль, написанный, скажем, на C++, который уже давно никем не сопровождается, то, чтобы его оживить, понадобится квалификация, скажем так, сильно отличающаяся от квалификации javascript-программиста.
На код можно взглянуть, с помощью которого сделан замер?
Не понял, какой смысл несет предикат f? Для assert'а же достаточно простого Tb — Ta < X. Или даже Tab < X, если в программе уже имеется вычисленная длительность интервала.
Да, слишком замороченный пример я выбрал. Вот другой, более программистский: assert'ы — утверждения, которые должны быть истинны в заданных точках выполнения программы. Часто эти утверждения зависят от истории вычислений. Например, мы хотим сказать, что между точкой А и точкой Б должно пройти не больше X мс. Тут нас не интересует дата-время, а только длительность интервала времени от А до Б. Это тоже формализация понятия о времени, но другая. Все, что я хотел сказать: универсальной формализации нет, она всегда зависит от задачи, когда попроще, когда посложнее.
Время, как дополнительная координата — это только один из вариантов. Есть задачи, где время надо понимать сложнее. Например, если нам требуется выразить, что с течением времени наши знания растут (т.е. мы допускаем незнание об истинности некоторых утверждений, но однажды обретенное знание — не меняется и не теряется) и мы хотим понять, какими эти знания могут стать (или могли быть), а какими — нет. Вот тут и появляются модели Крипке.
А про неразрешимость я вроде бы ничего не говорил, только про зависимость решения от задачи.

Information

Rating
Does not participate
Location
Россия
Registered
Activity