Ты правильно используешь коллекции в Java?
Не все коллекции одинаково полезны, и неправильный выбор может увеличить нагрузку на CPU или память в 10 раз, даже не замечая этого. Если работаешь с большими коллекциями, это важно:
1. ArrayList
Идеально, когда:
Читаешь много, а пишешь мало.
Доступ к элементам по позиции (get(i)).
Почему? Внутри — массив. Чтение очень быстрое, но вставка или удаление в середине медленные, потому что нужно сдвигать элементы.
Используй для: каталогов, списков, которые почти не меняются, или результатов, которые создаются один раз и потом только читаются.
2. LinkedList
Идеально, когда:
Постоянно добавляешь или удаляешь элементы.
Не нужен прямой доступ к элементу по индексу.
Каждый элемент знает, кто перед ним и кто после, поэтому вставка/удаление быстрые, но поиск конкретного элемента медленный, так как нужно проходить список поэлементно.
Используй для: очередей, буферов или структур, где важен порядок, а не скорость доступа.
3. HashMap
Идеально, когда:
Нужно хранить пары ключ/значение.
Требуется быстрый доступ по ключу (как словарь).
Использует функцию хеширования для быстрого поиска. Если hashCode() реализован плохо, может работать медленно и потреблять больше памяти.
Используй для: хранения пользователей, продуктов, настроек или любых данных, к которым нужен быстрый доступ по ключу.
Перед оптимизацией спроси себя:
Много читаю и мало пишу? → ArrayList
Часто вставляю/удаляю? → LinkedList
Ищу по ключу? → HashMap
Нет универсально «лучшей» структуры. Есть та, которая подходит под твой способ доступа к данным.
👉 Java Portal
Не все коллекции одинаково полезны, и неправильный выбор может увеличить нагрузку на CPU или память в 10 раз, даже не замечая этого. Если работаешь с большими коллекциями, это важно:
1. ArrayList
Идеально, когда:
Читаешь много, а пишешь мало.
Доступ к элементам по позиции (get(i)).
Почему? Внутри — массив. Чтение очень быстрое, но вставка или удаление в середине медленные, потому что нужно сдвигать элементы.
Используй для: каталогов, списков, которые почти не меняются, или результатов, которые создаются один раз и потом только читаются.
2. LinkedList
Идеально, когда:
Постоянно добавляешь или удаляешь элементы.
Не нужен прямой доступ к элементу по индексу.
Каждый элемент знает, кто перед ним и кто после, поэтому вставка/удаление быстрые, но поиск конкретного элемента медленный, так как нужно проходить список поэлементно.
Используй для: очередей, буферов или структур, где важен порядок, а не скорость доступа.
3. HashMap
Идеально, когда:
Нужно хранить пары ключ/значение.
Требуется быстрый доступ по ключу (как словарь).
Использует функцию хеширования для быстрого поиска. Если hashCode() реализован плохо, может работать медленно и потреблять больше памяти.
Используй для: хранения пользователей, продуктов, настроек или любых данных, к которым нужен быстрый доступ по ключу.
Перед оптимизацией спроси себя:
Много читаю и мало пишу? → ArrayList
Часто вставляю/удаляю? → LinkedList
Ищу по ключу? → HashMap
Нет универсально «лучшей» структуры. Есть та, которая подходит под твой способ доступа к данным.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11❤4
Please open Telegram to view this post
VIEW IN TELEGRAM
❤17🤣2
This media is not supported in your browser
VIEW IN TELEGRAM
Gitvizz превращает код в интерактивный граф
Терялся в собственном коде?
Встречай Gitvizz — инструмент, который мгновенно превращает кодовую базу в интерактивные графы, чтобы наглядно увидеть, как всё связано.
Посмотреть можно на gitvizz.com
👉 Java Portal
Терялся в собственном коде?
Встречай Gitvizz — инструмент, который мгновенно превращает кодовую базу в интерактивные графы, чтобы наглядно увидеть, как всё связано.
Посмотреть можно на gitvizz.com
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6👍4
Что такое String Pool
String Pool → это специальная область памяти внутри heap, где Java хранит строковые литералы.
Главная идея → повторное использование строк и экономия памяти.
Как это работает:
s1 и s2 указывают на один и тот же объект в String Pool → дубликаты не создаются.
Но если сделать так:
new String() обходит пул и создаёт новый объект в heap.
Зачем это нужно:
→ Экономит память за счёт переиспользования неизменяемых строк.
→ Повышает производительность при повторных строковых значениях.
→ Безопасно для потоков, потому что строки immutable.
Как заставить строку из heap использовать пул?
Ответ:
Метод intern() → добавляет строку в пул и возвращает ссылку на объект из пула.
👉 Java Portal
String Pool → это специальная область памяти внутри heap, где Java хранит строковые литералы.
Главная идея → повторное использование строк и экономия памяти.
Как это работает:
String s1 = "Java";
String s2 = "Java";
System.out.println(s1 == s2); // true
s1 и s2 указывают на один и тот же объект в String Pool → дубликаты не создаются.
Но если сделать так:
String s3 = new String("Java");
System.out.println(s1 == s3); // false
new String() обходит пул и создаёт новый объект в heap.
Зачем это нужно:
→ Экономит память за счёт переиспользования неизменяемых строк.
→ Повышает производительность при повторных строковых значениях.
→ Безопасно для потоков, потому что строки immutable.
Как заставить строку из heap использовать пул?
Ответ:
s3 = s3.intern();
Метод intern() → добавляет строку в пул и возвращает ссылку на объект из пула.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤5
Топ-20 вопросов по микросервисам для Java-разработчиков
На Java67 вышла подборка самых частых вопросов по микросервисной архитектуре — от отличий монолита до тем вроде Docker, Kubernetes, API Gateway, CQRS и Saga-паттернов.
👉 Java Portal
На Java67 вышла подборка самых частых вопросов по микросервисной архитектуре — от отличий монолита до тем вроде Docker, Kubernetes, API Gateway, CQRS и Saga-паттернов.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5👍2🤔1
Сценарный вопрос с реального интервью по Java/Spring Boot:
В контроллере вызывается метод сервиса, помеченный аннотацией
Этот метод не только сохраняет сущность, но и отправляет два письма: одно администратору, другое — пользователю, который сделал запрос.
Класс, отвечающий за отправку почты, помечен аннотацией
В итоге API обрабатывает запрос целых 12 секунд — очевидно, это неприемлемо.
Вопрос: почему так происходит и как это исправить?
Реальная причина:
Когда используется
Если внутри этого же контекста вызывается
Иными словами, асинхронный код оказывается «заперт» внутри транзакции.
В результате, коммит в базу ждёт, пока оба письма не будут отправлены.
Как исправить:
Заменить прямой вызов отправки писем на event-publisher подход.
После сохранения запроса просто опубликовать событие, например DemoRequestCreatedEvent.
Асинхронные слушатели (
Что получаем:
Транзакция завершается за ~100 мс вместо 12 секунд.
API реагирует почти мгновенно.
Письма всё так же надёжно уходят в фоне.
Использование событий и асинхронных слушателей — не просто красивая архитектурная штука, а реальный способ сделать систему быстрой, масштабируемой и профессиональной.
Дополнительный вопрос:
Кроме событий, какие подходы ты используешь, чтобы отделить транзакционную логику (например, коммит в БД) от побочных эффектов вроде отправки писем или уведомлений?
@Java_Iibrary
В контроллере вызывается метод сервиса, помеченный аннотацией
@Transactional
.Этот метод не только сохраняет сущность, но и отправляет два письма: одно администратору, другое — пользователю, который сделал запрос.
Класс, отвечающий за отправку почты, помечен аннотацией
@Async
, но Spring всё равно выполняет его синхронно.В итоге API обрабатывает запрос целых 12 секунд — очевидно, это неприемлемо.
Вопрос: почему так происходит и как это исправить?
Реальная причина:
Когда используется
@Transactional
, Spring создаёт прокси для транзакции.Если внутри этого же контекста вызывается
@Async
-метод, то Spring не создаёт новый поток — потому что вызов происходит внутри того же прокси.Иными словами, асинхронный код оказывается «заперт» внутри транзакции.
В результате, коммит в базу ждёт, пока оба письма не будут отправлены.
Как исправить:
Заменить прямой вызов отправки писем на event-publisher подход.
После сохранения запроса просто опубликовать событие, например DemoRequestCreatedEvent.
Асинхронные слушатели (
@EventListener
+ @Async
) будут обрабатывать отправку писем вне основной транзакции.Что получаем:
Транзакция завершается за ~100 мс вместо 12 секунд.
API реагирует почти мгновенно.
Письма всё так же надёжно уходят в фоне.
Использование событий и асинхронных слушателей — не просто красивая архитектурная штука, а реальный способ сделать систему быстрой, масштабируемой и профессиональной.
Дополнительный вопрос:
Кроме событий, какие подходы ты используешь, чтобы отделить транзакционную логику (например, коммит в БД) от побочных эффектов вроде отправки писем или уведомлений?
@Java_Iibrary
👍9❤2
This media is not supported in your browser
VIEW IN TELEGRAM
Хочешь сделать крутой GitHub-профиль?
На этом сайте собраны десятки классных README от разработчиков со всего мира. Можно смотреть код, вдохновляться, подхватывать идеи и оформить свой профиль так, чтобы он реально выделялся.
github.com/zzetao/awesome-github-profile
👉 Java Portal
На этом сайте собраны десятки классных README от разработчиков со всего мира. Можно смотреть код, вдохновляться, подхватывать идеи и оформить свой профиль так, чтобы он реально выделялся.
github.com/zzetao/awesome-github-profile
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5👍3
В Java есть одно зарезервированное слово, которое многие не замечают — yield.
Оно появилось в Java 13 вместе с switch expressions.
yield используется, чтобы вернуть значение из блока case, когда нужно выполнить несколько действий перед тем, как определить результат.
Пример:
yield — не то же самое, что break:
break просто прерывает выполнение;
yield возвращает значение блока в switch, который используется как выражение.
🌟
👉 Java Portal
Оно появилось в Java 13 вместе с switch expressions.
yield используется, чтобы вернуть значение из блока case, когда нужно выполнить несколько действий перед тем, как определить результат.
Пример:
int day = 2;
String result = switch (day) {
case 1 -> "Понедельник";
case 2 -> {
System.out.println("Обработка...");
yield "Вторник"; // значение, которое возвращается
}
default -> "Другой день";
};
yield — не то же самое, что break:
break просто прерывает выполнение;
yield возвращает значение блока в switch, который используется как выражение.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13❤6
15 октября(уже завтра!) в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle Java-разработчика.
Как это будет:
Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для Java-разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы.
Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_sh_bot
Реклама.
О рекламодателе.
Please open Telegram to view this post
VIEW IN TELEGRAM
Шаг за шагом проектируем сокращатель ссылок
В статье разбираем System Design на реальном примере = создаем свой сервис сокращения ссылок. Это классическая задача, которую часто дают на собеседованиях, и при этом отличная возможность понять, как устроен процесс проектирования систем: от постановки задачи до расчёта нагрузки и продумывания архитектуры.
👉 Java Portal
В статье разбираем System Design на реальном примере = создаем свой сервис сокращения ссылок. Это классическая задача, которую часто дают на собеседованиях, и при этом отличная возможность понять, как устроен процесс проектирования систем: от постановки задачи до расчёта нагрузки и продумывания архитектуры.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4
В Spring Boot можно включить «мягкое» завершение приложения, добавив в конфиг строку: "
Это помогает избежать типичных проблем при остановке сервиса:
- Активные HTTP-запросы обрываются посреди выполнения
- Транзакции в базе откатываются неожиданно
- Потоки прерываются до завершения работы
👉 Java Portal
server.shutdown=graceful
" server:
shutdown: graceful
spring:
lifecycle:
timeout-per-shutdown-phase: 20s
# Сервер будет завершать работу корректно
# Он даст до 20 секунд на завершение всех запросов и бинов.
Это помогает избежать типичных проблем при остановке сервиса:
- Активные HTTP-запросы обрываются посреди выполнения
- Транзакции в базе откатываются неожиданно
- Потоки прерываются до завершения работы
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11👀4
6.851 MIT: Продвинутые структуры данных (весна'21)
Этот курс давно был у меня в списке рекомендаций. Разбор темы иерархии памяти там отлично подан в контексте cache-oblivious алгоритмов.
https://courses.csail.mit.edu/6.851/spring21/
👉 Java Portal
Этот курс давно был у меня в списке рекомендаций. Разбор темы иерархии памяти там отлично подан в контексте cache-oblivious алгоритмов.
https://courses.csail.mit.edu/6.851/spring21/
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3👍2
Сборщик мусора (Garbage Collector, GC) сильно эволюционировал со временем. Сегодня есть несколько вариантов, и ты можешь выбрать тот, что подходит под твои нужды. Смотри:
- Serial GC (олдскул)
Самый простой и древний.
Один поток, останавливает всё приложение на время очистки памяти.
Подходит для мелких приложений, CLI-инструментов или систем с маленьким heap (пара десятков мегабайт).
- Parallel GC
По сути, тот же Serial, но работает в несколько потоков.
Паузы всё ещё есть, но они короче.
Хорош для batch-задач или сервисов, где короткая остановка не критична.
- G1 GC (Garbage First)
С Java 9 — сборщик по умолчанию.
Делит heap на регионы и чистит только самые “грязные”.
Даёт меньше пауз и предсказуемее поведение.
Оптимальный выбор для большинства продакшен-приложений: Spring, микросервисы и т. д.
- ZGC (Z Garbage Collector)
Паузы меньше 1 мс даже при heap в сотни гигабайт.
Работает почти полностью конкурентно, фактически в реальном времени.
Подходит для систем, которые не могут останавливаться: трейдинг, онлайн-игры, API с высокой доступностью.
- Shenandoah GC
Похож на ZGC, но реализован по-другому (Red Hat).
Тоже стремится к минимальным паузам, отлично чувствует себя на Linux.
Менее популярный, но стабильный вариант.
Что выбрать?
Небольшие приложения → Serial
Batch-процессы → Parallel
Веб-сервисы, микросервисы → G1
Реальное время, критичная задержка → ZGC или Shenandoah
GC уже давно не “та самая штука, что стопит Java”, а гибкий инструмент, который можно подобрать под задачу.
И от этого выбора реально зависит будет твое приложение тормозить… или летать
👉 Java Portal
- Serial GC (олдскул)
Самый простой и древний.
Один поток, останавливает всё приложение на время очистки памяти.
Подходит для мелких приложений, CLI-инструментов или систем с маленьким heap (пара десятков мегабайт).
- Parallel GC
По сути, тот же Serial, но работает в несколько потоков.
Паузы всё ещё есть, но они короче.
Хорош для batch-задач или сервисов, где короткая остановка не критична.
- G1 GC (Garbage First)
С Java 9 — сборщик по умолчанию.
Делит heap на регионы и чистит только самые “грязные”.
Даёт меньше пауз и предсказуемее поведение.
Оптимальный выбор для большинства продакшен-приложений: Spring, микросервисы и т. д.
- ZGC (Z Garbage Collector)
Паузы меньше 1 мс даже при heap в сотни гигабайт.
Работает почти полностью конкурентно, фактически в реальном времени.
Подходит для систем, которые не могут останавливаться: трейдинг, онлайн-игры, API с высокой доступностью.
- Shenandoah GC
Похож на ZGC, но реализован по-другому (Red Hat).
Тоже стремится к минимальным паузам, отлично чувствует себя на Linux.
Менее популярный, но стабильный вариант.
Что выбрать?
Небольшие приложения → Serial
Batch-процессы → Parallel
Веб-сервисы, микросервисы → G1
Реальное время, критичная задержка → ZGC или Shenandoah
GC уже давно не “та самая штука, что стопит Java”, а гибкий инструмент, который можно подобрать под задачу.
И от этого выбора реально зависит будет твое приложение тормозить… или летать
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10❤4
Transactions_and_Concurrency_Control.pdf
6.3 MB
Если ты работаешь с Java, очень советую почитать последнее издание “Troubleshooting Java”
В книге куча практических вещей: от лучших практик отладки до логирования, трейсинга, телеметрии, модели памяти Java, предотвращения дедлоков, профайлинга и сэмплинга.
Отличное чтиво, если хочешь реально понимать, что происходит под капотом JVM и как быстро находить проблемы в проде.
👉 Java Portal
В книге куча практических вещей: от лучших практик отладки до логирования, трейсинга, телеметрии, модели памяти Java, предотвращения дедлоков, профайлинга и сэмплинга.
Отличное чтиво, если хочешь реально понимать, что происходит под капотом JVM и как быстро находить проблемы в проде.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8
Может ли статический блок выбросить исключение?
У тебя есть класс, который инициализирует какой-то критически важный статический ресурс внутри статического блока. В процессе инициализации может произойти ошибка, и выбросится исключение. Что произойдет, если исключение будет выброшено из статического инициализатора? Какую ошибку в итоге выбросит JVM, и в каком состоянии останется класс после этого?
Подсказка → Если из статического блока выбрасывается исключение, инициализация класса завершается с ошибкой.
Есть ли в Java концепция выбрасывания исключений конструктором?
Ты создаешь класс DatabaseConnection. В конструкторе происходит попытка установить соединение с базой данных, и если это не удается, выбрасывается SQLException. Что произойдет с памятью, выделенной под объект DatabaseConnection, если конструктор выбросит исключение? Можно ли использовать объект после того, как исключение было выброшено?
Подсказка → Конструкторы могут (и часто должны) выбрасывать исключения, если объект невозможно создать в корректном состоянии.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤2
Хочешь учить и практиковать SQL без установки ничего на компьютер?
Есть классный ресурс и всё работает прямо в браузере.
Можно создавать базы MySQL и PostgreSQL, писать запросы и сразу видеть результат.
Бесплатно → http://sqlplayground.app
👉 Java Portal
Есть классный ресурс и всё работает прямо в браузере.
Можно создавать базы MySQL и PostgreSQL, писать запросы и сразу видеть результат.
Бесплатно → http://sqlplayground.app
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤2
Почему важно давать хорошие имена в коде?
Потому что большую часть времени мы не пишем код, а читаем его. И одно удачное имя способно объяснить то, что комментарий бы растянул на три строки.
Что решает хорошее имя:
Намерение: expireSession() говорит больше, чем process().
Контекст: calculatePriceWithTax() понятнее, чем просто calculate().
Контракт: isEmpty() (логический результат) и getSize() (число) — разное поведение, и имя это чётко показывает.
Простые, но работающие правила:
Глагол + объект для действий: sendInvoiceEmail().
Ясное существительное для данных: PaymentRequest, CustomerId.
Без тайнописи вроде cfg, mgr, tmp2.
Если логика нетривиальна, пусть имя объясняет “почему”: retryOnRateLimit().
А комментарии не нужны?🤔
Нужны, но точечно. Пиши их там, где код сам не может выразить мысль:
когда решение неочевидное;
когда нужна историческая справка или ссылка на ADR.
Главное не использовать комментарии, чтобы объяснять то, что код и так должен рассказывать сам.
👉 Java Portal
Потому что большую часть времени мы не пишем код, а читаем его. И одно удачное имя способно объяснить то, что комментарий бы растянул на три строки.
Что решает хорошее имя:
Намерение: expireSession() говорит больше, чем process().
Контекст: calculatePriceWithTax() понятнее, чем просто calculate().
Контракт: isEmpty() (логический результат) и getSize() (число) — разное поведение, и имя это чётко показывает.
Простые, но работающие правила:
Глагол + объект для действий: sendInvoiceEmail().
Ясное существительное для данных: PaymentRequest, CustomerId.
Без тайнописи вроде cfg, mgr, tmp2.
Если логика нетривиальна, пусть имя объясняет “почему”: retryOnRateLimit().
А комментарии не нужны?
Нужны, но точечно. Пиши их там, где код сам не может выразить мысль:
когда решение неочевидное;
когда нужна историческая справка или ссылка на ADR.
Главное не использовать комментарии, чтобы объяснять то, что код и так должен рассказывать сам.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13❤2
Топ-20 техник оптимизации SQL-запросов
1. Индексируй под реальные паттерны запросов (композитные, селективные, covering-индексы), а не просто по числу строк. Следи, чтобы статистика была актуальной.
2. Используй
3. Выбирай конкретные колонки, не пиши SELECT *, чтобы сократить I/O и дать шанс использовать covering-индекс.
4. Пиши sargable-предикаты (которые могут использовать индекс). Медленные коррелированные подзапросы лучше переписать через JOIN или EXISTS.
5. Не лечи ошибки DISTINCT’ом. Исправь логику JOIN и ключи; DISTINCT — только когда реально нужно убрать дубликаты.
6. Фильтруй в
7. Пиши явные
8. Используй keyset pagination вместо OFFSET/LIMIT на больших наборах; для выборки подмножества можно применить TABLESAMPLE (если поддерживается).
9. Предпочитай
10. Заменяй широкие
11. Тяжёлые запросы запускай вне пиковых часов, при возможности — ограничивай ресурсы или ставь в очередь.
12. Избегай
13. Используй
14. Используй временные/derived таблицы, если они реально сокращают работу или добавляют статистику; но помни, что это может заблокировать pushdown-оптимизации.
15. При массовой загрузке данных отключай/удаляй некластерные индексы, вставляй пакетами, потом перестраивай. PK/кластерный индекс можно оставить, если помогает.
16. Используй материализованные представления для редко меняющихся и дорогих агрегатов, продумай их обновление и инвалидацию.
17. Избегай не-sargable сравнений (например, <>) по малоселективным колонкам; лучше перепиши в диапазоны.
18. Минимизируй коррелированные подзапросы на больших выборках, переходи на join’ы или EXISTS.
19. Выбирай
20. Кешируй часто повторяющиеся выборки: временные таблицы (на сессию), result cache или материализованные представления с продуманными правилами обновления.
Что такое Query Optimizer
Query Optimizer — это компонент СУБД, который определяет наиболее эффективный способ выполнения SQL-запроса, подбирая оптимальный execution plan.
Он принимает SQL-запрос, парсит его и строит синтаксическое дерево. Затем анализирует дерево, чтобы понять, какие способы выполнения возможны.
Далее оптимизатор генерирует альтернативные execution plans — разные варианты выполнения одного и того же запроса. В каждом плане задаётся:
- порядок доступа к таблицам
- типы соединений
- способы фильтрации и сортировки
Каждому плану присваивается стоимость — оценка по числу чтений с диска, времени CPU и другим факторам.
После этого оптимизатор выбирает план с минимальной стоимостью и использует его для реального выполнения запроса.
Узнай больше
👉 Java Portal
1. Индексируй под реальные паттерны запросов (композитные, селективные, covering-индексы), а не просто по числу строк. Следи, чтобы статистика была актуальной.
2. Используй
EXISTS
для проверки наличия данных; COUNT(*) — только если реально нужен подсчёт. 3. Выбирай конкретные колонки, не пиши SELECT *, чтобы сократить I/O и дать шанс использовать covering-индекс.
4. Пиши sargable-предикаты (которые могут использовать индекс). Медленные коррелированные подзапросы лучше переписать через JOIN или EXISTS.
5. Не лечи ошибки DISTINCT’ом. Исправь логику JOIN и ключи; DISTINCT — только когда реально нужно убрать дубликаты.
6. Фильтруй в
WHERE
, а HAVING используй только для условий после агрегации. 7. Пиши явные
JOIN ... ON
, не лепи неявные join’ы через WHERE. 8. Используй keyset pagination вместо OFFSET/LIMIT на больших наборах; для выборки подмножества можно применить TABLESAMPLE (если поддерживается).
9. Предпочитай
UNION ALL
вместо UNION
, если дубликаты допустимы. 10. Заменяй широкие
OR
на UNION ALL
, только если каждая ветка может использовать свой индекс. 11. Тяжёлые запросы запускай вне пиковых часов, при возможности — ограничивай ресурсы или ставь в очередь.
12. Избегай
OR
в условиях JOIN
, можно использовать вычисляемые колонки или UNION ALL, если это позволит использовать индекс. 13. Используй
GROUP BY
, когда нужны агрегированные строки, и оконные функции — когда нужно видеть строки с агрегатами рядом. 14. Используй временные/derived таблицы, если они реально сокращают работу или добавляют статистику; но помни, что это может заблокировать pushdown-оптимизации.
15. При массовой загрузке данных отключай/удаляй некластерные индексы, вставляй пакетами, потом перестраивай. PK/кластерный индекс можно оставить, если помогает.
16. Используй материализованные представления для редко меняющихся и дорогих агрегатов, продумай их обновление и инвалидацию.
17. Избегай не-sargable сравнений (например, <>) по малоселективным колонкам; лучше перепиши в диапазоны.
18. Минимизируй коррелированные подзапросы на больших выборках, переходи на join’ы или EXISTS.
19. Выбирай
INNER
или LEFT/RIGHT
по смыслу, но помни: INNER JOIN обычно быстрее, если подходит по логике. 20. Кешируй часто повторяющиеся выборки: временные таблицы (на сессию), result cache или материализованные представления с продуманными правилами обновления.
Что такое Query Optimizer
Query Optimizer — это компонент СУБД, который определяет наиболее эффективный способ выполнения SQL-запроса, подбирая оптимальный execution plan.
Он принимает SQL-запрос, парсит его и строит синтаксическое дерево. Затем анализирует дерево, чтобы понять, какие способы выполнения возможны.
Далее оптимизатор генерирует альтернативные execution plans — разные варианты выполнения одного и того же запроса. В каждом плане задаётся:
- порядок доступа к таблицам
- типы соединений
- способы фильтрации и сортировки
Каждому плану присваивается стоимость — оценка по числу чтений с диска, времени CPU и другим факторам.
После этого оптимизатор выбирает план с минимальной стоимостью и использует его для реального выполнения запроса.
Узнай больше
Please open Telegram to view this post
VIEW IN TELEGRAM
❤11👍3
Чтобы сделать API быстрым, нужно получать данные из нескольких микросервисов параллельно. Как это требование влияет на выбор между RestTemplate, WebClient и Feign Client?
RestTemplate: Подходит для простых, блокирующих сценариев — например, в старом Spring MVC-приложении, где нужно сделать вызов к другому сервису и дождаться ответа, прежде чем продолжить выполнение. RestTemplate считается устаревшим, вместо него рекомендуется использовать RestClient.
WebClient: Предпочтительный вариант для высокопроизводительных неблокирующих приложений, например, для API-шлюзов, которым нужно одновременно обращаться к нескольким микросервисам и объединять результаты без блокировки потоков.
Feign Client: Лучше всего подходит для взаимодействия между микросервисами, когда хочется писать чистый, читаемый код на основе интерфейсов, абстрагирующий детали HTTP-запросов.
👉 Java Portal
RestTemplate: Подходит для простых, блокирующих сценариев — например, в старом Spring MVC-приложении, где нужно сделать вызов к другому сервису и дождаться ответа, прежде чем продолжить выполнение. RestTemplate считается устаревшим, вместо него рекомендуется использовать RestClient.
WebClient: Предпочтительный вариант для высокопроизводительных неблокирующих приложений, например, для API-шлюзов, которым нужно одновременно обращаться к нескольким микросервисам и объединять результаты без блокировки потоков.
Feign Client: Лучше всего подходит для взаимодействия между микросервисами, когда хочется писать чистый, читаемый код на основе интерфейсов, абстрагирующий детали HTTP-запросов.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Javaeros! Они сделали MCP официального Java SDK — так что нам больше не придётся разбираться с древней документацией 💪
github.com/modelcontextprotocol/java-sdk
Рекомендация перед использованием: сначала разберись, что вообще такое MCP - пойми саму концепцию. После этого реализация, независимо от языка, уже вопрос синтаксиса.
👉 Java Portal
github.com/modelcontextprotocol/java-sdk
Рекомендация перед использованием: сначала разберись, что вообще такое MCP - пойми саму концепцию. После этого реализация, независимо от языка, уже вопрос синтаксиса.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5