Comments 38
Почему нельзя задать диапазоны в базе 10-значным числом и просто делать поиск по диапазону?
CREATE INDEX ON phonecodes USING gist(int8range((code || numb)::bigint, (code || nume)::bigint, '[]'));
SELECT
*
FROM
phonecodes
WHERE
int8range((code || numb)::bigint, (code || nume)::bigint, '[]') @> '[4852262000, 4852262000]'::int8range;
Правда, с теми же номерами с «цифрой A» обломится.
У вас АТС прямо в базу ходит? Отрезать что-то не проблема, думаю.
Опять же, зачем все так сложно?
Вы все-равно парсите номера скриптом, можно же склеить префикс и диапазон в одно число в момент загрузки данных в базу. В итоге будет два числа границ диапазона и обычный поиск по дереву where phone >= numb and phone <= nume.
val BETWEEN col1 AND col2
, если имеется в виду btree?Да, тут я ступил. Ну сразу делать колонку int8range.
Или, с учетом того, что диапазоны у нас не пересекаются, просто nume >= phone order by nume limit 1 и потом уже проверить на numb эту одну строку.
378 тысяч ключей это ерунда.
10 запросов на звонок в худшем случае. Ерунда.
Если нужны миллисекунды паралелим. Тут чуть сложнее, но тоже тривиально все.
В качестве бонуса в тот же kv кладем всех клиентов. Если у вас их сколь либо адекватное количество работать отлично будет.
Сложностью. Мое решение описывается двумя предложениями, реализуется джуном за день. Ваше даже в словах сложное.
substr(pfx, 1, length(pfx) - 1) -- "отщипываем" последнюю цифру
Это же ровно тот же алгоритм:
запрос от номера минус последняя цифра и так далее пока не найдется
Сложность это не только конечный код. Сложность это все от тикета с задачей до готового кода.
В моем варианте негде ошибаться, понятно как писать тесты, понятно что с производительностью, производительность не надо оптимизировать, да и сама задача джуну на день написать код, и мне 10 минут на написать тикет.
У вас все гораздо сложнее.
Точно ли не надо оптимизировать производительность? Поставим какой-нибудь Redis на площадке в Мск и будем делать к нему последовательно те самые 10 запросов из Владивостока, получая на каждом задержку до 150мс… Делать параллельно? Так это же уже оптимизация, и не для всякого джуна.
Это не имеет никакого отношения к теме статьи, а исключительно холивар SQL vs NoSQL. Есть задачи, где выигрывает NoSQL, есть — где SQL, есть где они равноприменимы, как тут.
У вас абстракции протекли.
Возможность без спец ухищрений сделать базу в 150мс от бека это ошибка другого уровня. Ее тоже надо исправлять, но к этой задаче это не имеет отношения.
Мое решение описывается двумя предложениями, реализуется джуном за день.
В моем варианте негде ошибаться, понятно как писать тесты, понятно что с производительностью, производительность не надо оптимизировать, да и сама задача джуну на день написать код, и мне 10 минут на написать тикет.
А оказывается, что именно решение, как цельный законченный функционал — не работает!
150мс от бека это ошибка другого уровня. Ее тоже надо исправлятьНу так и где оно «проще», если там нужно еще дополнительную кучу граничных условий учитывать? То есть это заведомо не «постановка за 10 минут».
За 10. Исходим из разумных предположений. Предположить что небольшая kv база рядом с бекендом разумно. Предполагать что она через океан неразумно.
Исправление ошибок архитектуры, а kv база в 150мс от бекенда это ошибка архитектуры, никак не связано с разработкой бизнес логики. Тут же чистая разработка бизнес логики.
Смешивать такие вещи это и есть протекающие абстракции.
— делать 10 запросов к БД вместо 1 — ошибка архитектуры приложения, поскольку увеличивает нагрузку на нее, плюс лишний трафик, плюс задержки
— делать запросы последовательно — тоже ошибка архитектуры
— взять KV без поддержки префиксного поиска — туда же
Ими мы не занимаемся. Поэтому к концу дня приходит гордый джун: "Смотри, я сделал ничего. Оно идеально [не] работает — все тесты это показывают. Но у меня нет ни одной ошибки! Зато вот в архитектуре — сплошные..."
И таки он прав — это не его ошибки, а того, кто его отправил неправильной дорогой за те самые 10 минут — если под «джуном» мы понимаем обычного простого кодера, а не того, кто стремится вырасти до «сеньора».
10, да и любое другое разумное фиксированное число обращений к kv это правильно и хорошо. Kv созданы для такой нагрузки и хорошо умеют ее обрабатывать. Это типовой паттерн использования.
За все фичи, в том числе префиксные поиски, надо платить. Как правило это не имеет смысла. У нас типичный О(1) с разумной константой. Смысл что-то там городить?
Если джун нашел ошибки архитектуры на уровне планирования ДЦ баз и бекендов то надо что-то в консерватории менять. И это что-то никак не связано с реализацией бизнес логики.
У нас типичный О(1) с разумной константой. Смысл что-то там городить?Вы вторую часть статьи про префиксный поиск по reverse точно прочитали?
Если джун не смог нормально решить поставленную задачу указанными инструментами, то не факт, что проблема в нем или в архитектуре. Возможно, она в том, кто ему указал решать эту задачу именно этими инструментами.
Я это и называю жутким переусложнением.
Задача решается однострочником. С нормальным и предсказуемым быстродействием. При этом не делается ни одного неразумного предположения о проекте или инфраструктуре.
Ну что еще надо?
IntStream.range(0, str.length()).mapToObj(i -> str.substring(0, str.length() - i)).parallel().map(this::redisReq).filter(Objects::nonNull).findFirst();
oldblog.antirez.com/post/autocomplete-with-redis.html
И сравните с краткостью и выразительностью
CREATE INDEX (varchar_pattern_ops) / SELECT ... LIKE
.Творить из хорошей kv плохую «любую другую» базу не надо.
Надо пользоваться преимущесвами kv. Она держит безумный рпс на смешном железе. И при этом очень быстро работает. Надо этим пользоваться.
Или все-таки все зависит от задачи?
Это не имеет никакого отношения к теме статьи, а исключительно холивар SQL vs NoSQL. Есть задачи, где выигрывает NoSQL, есть — где SQL, есть где они равноприменимы
День на перекладывание джейсонов, тесты и прочий бойлерплейт.
Конечно зависит. sql великолепен. Но тут он не нужен.
Равноприменимы — не верю. Слишком оно разное. Использование не того что нужно для конкретной задачи вызывает как минимум усложнение кода. Где код и проектирование получаются проще, то и надо использовать.
Ваш пример это отлично иллюстрирует. Варианты реализации, профайлеры, планы запросов. Море всего. У меня же одна строка. Понятно как она работает, понятно быстродействие, понятны ограничения. Не надо вообще ничего больше делать.
Общие ограничения любой БД знать полезно. Чтобы случайно ужаса не сделать.
Изивините, но ваше решение выглядит сложнее в коде, чем простой sql заропс с поиском по специально предназначенному для таких целей индексу. Редис тут имеет смысл использовать только если для нас важно время ответа. Про rps я бы не был столь уверен, было бы интересно потестировать… равно как и потребление памяти.
За все фичи, в том числе префиксные поиски, надо платить. Как правило это не имеет смысла. У нас типичный О(1) с разумной константой. Смысл что-то там городить?
Если чо, то вы просто сделали префиксный поиск на редисе со сложностью O(n).
Ну да, а потом условный джун внезапно узнает, что ключи в данной kv по префиксу не ищутся, ибо там хешмап.
У него тесты не сработают. Он пойдет почитает доку и все сделает правильно.
Для того и пишем интеграционные тесты.
Ага, и сделает поиск по маске в редисе, например ;)
Код ревью для кого придумали?
Если и ревьюер не в курсе и считает такой код ок, то пора нанимать людей подороже. С кадрами серьезные проблемы.
И что ревьювер в данном кейсе предложит сделать?
Предложит переписать код так чтобы не искать по маске? Можно приложить ссылочку где описано что так не оптимально делать.
Потом окажется, что искать на редисе по префиксу не так и просто, что нужно или сложную структуру придумывать или дублировать ключи, что увеличит объем данных раз 10. Что нужно искать другое nosql решение, которое хотя бы умеет btree, что бы искать по префиксу… и внезапно придете к тем же запросам, что и в статье, только может не на sql. Вы все еще считаете, что nosql решение сильно "элементарнее", чем написать один sql запрос на постгресе, который давно работает, проверен, по нему хорошая экспертиза?
Актуальные данные мобильных операторов нужно брать здесь: zniis.ru/bdpn/check
У меня зазвонил телефон. Кто говорит?.. Поможет «слон»