Java | Вопросы собесов
11.4K subscribers
39 photos
3 videos
1.53K links
Сайт: https://easyoffer.ru/
Все каналы: t.me/+xGeAw6ckJ4liYzQy

Контакт для рекламы: @easyoffer_adv
Download Telegram
🤔 Для чего нужны паттерны программирования?

Паттерны проектирования (design patterns) — это готовые решения распространённых задач, возникающих при разработке программного обеспечения.

🚩Зачем они нужны?

🟠Структурируют код
помогают писать код понятнее и чище.
🟠Упрощают поддержку
делают код гибким и масштабируемым.
🟠Экономят время
не нужно изобретать велосипед, а можно использовать проверенные решения.
🟠Облегчают общение
разработчики могут быстро понимать, как устроена программа, если в ней используются известные паттерны.

🚩Виды паттернов программирования

🟠Порождающие (Creational)
управляют созданием объектов.
🟠Структурные (Structural)
Определяют, как классы и объекты взаимодействуют.
🟠Поведенческие (Behavioral)
управляют взаимодействием объектов и потоками выполнения.

public class Singleton {
private static Singleton instance;

private Singleton() {} // Закрытый конструктор

public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}


Структурные паттерны (определяют отношения между классами и объектами)
// Старый интерфейс
class OldPrinter {
void printText(String text) {
System.out.println("Печать: " + text);
}
}

// Новый интерфейс
interface ModernPrinter {
void print(String text);
}

// Адаптер
class PrinterAdapter implements ModernPrinter {
private final OldPrinter oldPrinter = new OldPrinter();

@Override
public void print(String text) {
oldPrinter.printText(text);
}
}

// Использование
public class AdapterExample {
public static void main(String[] args) {
ModernPrinter printer = new PrinterAdapter();
printer.print("Hello, world!");
}
}


import java.util.ArrayList;
import java.util.List;

// Интерфейс подписчика
interface Observer {
void update(String message);
}

// Интерфейс издателя
class NewsChannel {
private final List<Observer> observers = new ArrayList<>();

void subscribe(Observer observer) {
observers.add(observer);
}

void notifyObservers(String news) {
for (Observer observer : observers) {
observer.update(news);
}
}
}

// Подписчик
class Subscriber implements Observer {
private final String name;

Subscriber(String name) {
this.name = name;
}

@Override
public void update(String message) {
System.out.println(name + " получил новость: " + message);
}
}

// Использование
public class ObserverExample {
public static void main(String[] args) {
NewsChannel channel = new NewsChannel();
Observer user1 = new Subscriber("Алиса");
Observer user2 = new Subscriber("Боб");

channel.subscribe(user1);
channel.subscribe(user2);

channel.notifyObservers("Новый выпуск Java 21!");
}
}


Ставь 👍 и забирай 📚 Базу знаний
👍6
🤔 Что такое HashSet?

Это реализация Set, основанная на хеш-таблице, которая:
- не допускает дубликатов;
- не сохраняет порядок;
- обеспечивает быстрые операции добавления, удаления и поиска (O(1)).


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
👍5🔥2🤔2
🤔 Что знаешь об интерфейсе FileFilter?

FileFilter — это интерфейс в пакете java.io, используемый для фильтрации файлов в каталогах. Он применяется в методе listFiles(FileFilter filter) класса File и позволяет выбрать только те файлы, которые соответствуют заданным критериям.

🚩Как работает `FileFilter`?

Этот интерфейс содержит всего один метод:
boolean accept(File pathname);


🚩Пример использования `FileFilter`

Допустим, мы хотим отфильтровать все файлы .txt в заданной папке:
import java.io.File;
import java.io.FileFilter;

public class TxtFileFilterExample {
public static void main(String[] args) {
File directory = new File("C:/example"); // Укажите свою папку

// Используем FileFilter для выбора файлов с расширением .txt
FileFilter txtFilter = new FileFilter() {
@Override
public boolean accept(File file) {
return file.isFile() && file.getName().endsWith(".txt");
}
};

// Получаем список файлов, соответствующих фильтру
File[] txtFiles = directory.listFiles(txtFilter);

// Выводим найденные файлы
if (txtFiles != null) {
for (File file : txtFiles) {
System.out.println("Файл: " + file.getName());
}
}
}
}


Выходные данные (если в папке C:/example есть файлы .txt)
Файл: notes.txt
Файл: tasks.txt


🚩Lambda-версия (Java 8+)

Вместо анонимного класса можно использовать лямбда-выражение:
FileFilter txtFilter = file -> file.isFile() && file.getName().endsWith(".txt");


🚩Разница между `FileFilter` и `FilenameFilter`

FileFilter принимает объект File, позволяя фильтровать как файлы, так и каталоги.
FilenameFilter принимает только имя файла (без пути).
import java.io.File;
import java.io.FilenameFilter;

public class TxtFilenameFilterExample {
public static void main(String[] args) {
File directory = new File("C:/example");

// Фильтр для файлов .txt
FilenameFilter txtFilter = (dir, name) -> name.endsWith(".txt");

String[] txtFiles = directory.list(txtFilter);
if (txtFiles != null) {
for (String file : txtFiles) {
System.out.println("Файл: " + file);
}
}
}
}


Ставь 👍 и забирай 📚 Базу знаний
👍4
🤔 Какие есть ограничения на ключи?

- Primary Key:
- Должен быть уникален.
- Не допускает NULL.
- Foreign Key:
- Значение должно существовать в родительской таблице.
- Может ограничивать удаление или обновление (RESTRICT, CASCADE).
- Unique:
- Значение должно быть уникальным, но может быть NULL (в зависимости от СУБД).


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
👍4🔥1
🤔 Является ли пустым пул строк при старте jar файла или там есть какие-то значения?

Пул строк в Java не является пустым при старте JAR файла. Он изначально содержит несколько предопределенных строковых литералов, которые JVM использует для своей внутренней работы, а также строковые литералы, используемые в загруженных классах и стандартных библиотеках.

🚩Что изначально содержится

🟠Предопределенные строковые литералы
JVM и стандартные библиотеки Java используют различные строковые литералы для своей работы. Эти строки добавляются в пул строк при запуске JVM. Примеры таких строк включают имена основных классов и пакетов (например, "java/lang/Object", "java/lang/String").
🟠Строковые литералы, используемые в загруженных классах
Когда классы загружаются JVM, все строковые литералы, используемые в этих классах, добавляются в пул строк. Это включает строки, используемые в JAR файле, а также строки из стандартных библиотек Java, которые загружаются при старте.

🚩Пример строк в пуле при старте

Для демонстрации этого можно написать простой код, который проверяет, присутствуют ли определенные строки в пуле строк при старте программы.
public class StringPoolDemo {
public static void main(String[] args) {
// Проверка стандартных строк, которые могут быть в пуле строк
String str1 = "java";
String str2 = "lang";
String str3 = "Object";

// Вывод строк
System.out.println("str1: " + str1);
System.out.println("str2: " + str2);
System.out.println("str3: " + str3);

// Проверка строк в пуле строк
System.out.println("Is 'java' in pool: " + (str1 == "java"));
System.out.println("Is 'lang' in pool: " + (str2 == "lang"));
System.out.println("Is 'Object' in pool: " + (str3 == "Object"));
}
}


🚩Что происходит при старте JVM

🟠Инициализация JVM
При запуске JVM загружаются системные классы, такие как java.lang.Object, java.lang.String, java.lang.System, и другие. Строковые литералы, используемые в этих классах, добавляются в пул строк.
🟠Загрузка пользовательских классов
Когда JVM загружает пользовательские классы из JAR файла, все строковые литералы в этих классах также добавляются в пул строк.

Ставь 👍 и забирай 📚 Базу знаний
👍4🤔1💊1
🤔 Назови основные реализации Set.

- HashSet — неупорядоченное множество;
- LinkedHashSet — сохраняет порядок добавления;
- TreeSet — отсортированное множество.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
👍9
🤔 Слышал ли что то про цикл ForEach?

Цикл forEach – это удобный способ перебора элементов коллекций в Java.

🚩Что такое `forEach`?

Это специальный цикл, который упрощает перебор элементов коллекций и массивов. Он пришёл на замену классическому for и while, делая код чище.
List<String> names = List.of("Alice", "Bob", "Charlie");

for (int i = 0; i < names.size(); i++) {
System.out.println(names.get(i));
}


Современный forEach
for (String name : names) {
System.out.println(name);
}


🚩`forEach` как метод (Java 8+)

С выходом Java 8 в интерфейсе Iterable появился метод forEach(), который принимает лямбда-выражение.
List<String> names = List.of("Alice", "Bob", "Charlie");

names.forEach(name -> System.out.println(name));


Или с ссылкой на метод (::)
names.forEach(System.out::println);


🚩Как работает `forEach()` с Map?

Метод forEach() можно применять и к Map, передавая BiConsumer<K, V>.
Map<Integer, String> users = Map.of(1, "Alice", 2, "Bob");

users.forEach((id, name) -> System.out.println(id + " -> " + name));


Ставь 👍 и забирай 📚 Базу знаний
👍6💊3
🤔 Как долго в String хранятся строки?

Строки — неизменяемые (immutable) и живут в памяти столько, сколько на них существуют ссылки.
Если строка находится в String Pool'е, она хранится до завершения работы JVM, если не используется механизм очистки пула (в зависимости от версии Java и GC).
Обычные строки (например, созданные через new) живут как обычные объекты — пока есть ссылки, потом собираются сборщиком мусора.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
👍5🔥5
🤔 В чем разница между Statement и PreparedStatement?

Это два интерфейса в JDBC, которые используются для выполнения SQL-запросов к базе данных. Основные различия между ними касаются производительности, безопасности и удобства использования.

🚩Statement

Statement используется для выполнения простых SQL-запросов. Запросы формируются и передаются в базу данных в виде строки. Подходит для простых запросов. Не оптимизирован для повторного выполнения. Каждый раз, когда запрос передается в базу данных, он компилируется и выполняется заново. Уязвим к SQL-инъекциям. Поскольку запрос формируется путем конкатенации строк, злоумышленники могут внедрять вредоносный SQL-код.
Statement stmt = connection.createStatement();
String query = "SELECT * FROM employees WHERE department = 'HR'";
ResultSet rs = stmt.executeQuery(query);

while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
System.out.println("ID: " + id + ", Name: " + name);
}
stmt.close();


🟠PreparedStatement
PreparedStatement используется для выполнения предварительно скомпилированных SQL-запросов. Это позволяет повысить производительность и безопасность. Оптимизирован для повторного выполнения. Запрос компилируется только один раз, а затем может многократно выполняться с разными параметрами, что повышает производительность. Защита от SQL-инъекций. Использует параметризованные запросы, которые помогают избежать уязвимостей, связанных с SQL-инъекциями. Удобство работы с параметрами. Позволяет устанавливать значения параметров с использованием методов setInt(), setString() и других.
String query = "SELECT * FROM employees WHERE department = ?";
PreparedStatement pstmt = connection.prepareStatement(query);
pstmt.setString(1, "HR");
ResultSet rs = pstmt.executeQuery();

while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
System.out.println("ID: " + id + ", Name: " + name);
}
pstmt.close();


🚩Основные различия

🟠Производительность
Statement: Каждый запрос компилируется заново, что снижает производительность при многократном выполнении одного и того же запроса.
PreparedStatement: Запрос компилируется один раз и может многократно выполняться с разными параметрами, что повышает производительность.
🟠Безопасность
Statement: Уязвим к SQL-инъекциям, поскольку запросы формируются путем конкатенации строк.
PreparedStatement: Использует параметризованные запросы, что защищает от SQL-инъекций.
🟠Удобство использования
Statement: Подходит для простых, одноразовых запросов.
PreparedStatement: Удобен для многократного выполнения запросов с разными параметрами.
🟠Типы запросов
Оба интерфейса могут выполнять запросы типа SELECT, INSERT, UPDATE, DELETE, но PreparedStatement более удобен для запросов с параметрами.

Ставь 👍 и забирай 📚 Базу знаний
👍3
🤔 На основании какой структуры данных реализован LinkedList?

LinkedList построен на двусвязном списке. Каждый узел содержит:
- данные (значение);
- ссылку на предыдущий узел;
- ссылку на следующий узел.
Это обеспечивает эффективные операции вставки и удаления, особенно в начале и в середине, но доступ по индексу происходит линейно — O(n).


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
👍5
🤔 В чем разница JPQL и HQL?

JPQL (Java Persistence Query Language) и HQL (Hibernate Query Language) – это языки запросов, похожие на SQL, но работающие с объектами, а не с таблицами БД.
Главное отличие: JPQL – стандарт JPA, а HQL – специфичен для Hibernate.

🚩JPQL (Java Persistence Query Language)

Стандартный язык JPA, работает со всеми JPA-совместимыми провайдерами (Hibernate, EclipseLink, OpenJPA).
Опирается на JPA Entity-классы, а не на реальные таблицы в БД.
TypedQuery<User> query = entityManager.createQuery(
"SELECT u FROM User u WHERE u.age > :age", User.class);
query.setParameter("age", 18);
List<User> users = query.getResultList();


🚩HQL (Hibernate Query Language)

Язык запросов специфичный для Hibernate.
Работает аналогично JPQL, но поддерживает дополнительные возможности, например, вызов методов и фильтрацию по подзапросам.
Query query = session.createQuery(
"FROM User u WHERE LENGTH(u.name) > 5"); // Использование функции LENGTH()
List<User> users = query.list();


Ставь 👍 и забирай 📚 Базу знаний
👍7
🤔 Что содержит задача, которая пришла от аналитиков?

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


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
💊10🔥5🤔1
🤔 После какого момента GC понимает, что нужно собирать мусор?

Garbage Collector (GC) в Java начинает сборку мусора, когда объекты в памяти больше не используются и не имеют активных ссылок.

🟠Основное правило: объект считается мусором, если нет на него ссылок
GC понимает, что объект можно удалить, если на него больше не ссылается ни одна переменная или он стал недостижимым.
class Demo {
int value;
}

public class Main {
public static void main(String[] args) {
Demo obj = new Demo(); // Создан объект в памяти (Heap)
obj = null; // Теперь на него нет ссылки → GC его удалит
}
}


🚩Когда GC запускается?

🟠Недостаток памяти (Low Memory)
Если в куче (Heap) осталось мало свободной памяти, JVM может запустить GC.

🟠Алгоритмы JVM (GC работает автоматически)
GC в Java автоматический, и его запуск зависит от алгоритма сборщика мусора. Некоторые из них:
Serial GC (для маленьких программ)
Parallel GC (по умолчанию в Java 8)
G1 GC (по умолчанию в Java 11+)
ZGC, Shenandoah GC (для высоконагруженных систем)

🚩Способы обнаружения "мусора"

🟠Счётчик ссылок (Reference Counting)
Устарело, потому что не умеет работать с циклическими ссылками.
🟠Алгоритм "Reachability" (Достижимость)
Основной метод, который использует GC в Java.
🟠Алгоритм достижимости (Reachability Analysis)
GC начинает с корневых объектов (GC Roots) и проверяет, какие объекты достижимы.

Ставь 👍 и забирай 📚 Базу знаний
👍3💊3
🤔 Какие у нас есть терминальные операции?

В контексте Stream API терминальные операции — это финальные действия, после которых поток закрывается и дальнейшие промежуточные операции невозможны. Примеры:
- forEach — перебор элементов.
- collect — сбор в коллекцию.
- reduce — свёртка значений.
- count — подсчёт элементов.
- anyMatch / allMatch / noneMatch — логические проверки.
- findFirst / findAny — нахождение элемента.
- min / max — поиск минимального или максимального значения.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
👍5
🤔 Какие классы поддерживают чтение и запись потоков в компрессированном формате?

Java предоставляет встроенные классы для чтения и записи сжатых данных в формате ZIP, GZIP и других. Эти классы находятся в пакете java.util.zip.

🚩GZIP (формат `.gz`)

GZIPOutputStream – сжимает данные в формат .gz.
GZIPInputStream – разжимает данные из .gz.
import java.io.*;
import java.util.zip.*;

public class GZipExample {
public static void main(String[] args) throws IOException {
String data = "Привет, мир! Это тестовая строка для GZIP.";

// Сжатие в .gz
try (FileOutputStream fos = new FileOutputStream("data.gz");
GZIPOutputStream gzos = new GZIPOutputStream(fos)) {
gzos.write(data.getBytes());
}

// Разжатие .gz
try (FileInputStream fis = new FileInputStream("data.gz");
GZIPInputStream gzis = new GZIPInputStream(fis);
BufferedReader reader = new BufferedReader(new InputStreamReader(gzis))) {
System.out.println("Разжатый текст: " + reader.readLine());
}
}
}


🚩ZIP (формат `.zip`)

ZipOutputStream – создаёт ZIP-архив.
ZipInputStream – извлекает файлы из ZIP.
import java.io.*;
import java.util.zip.*;

public class ZipExample {
public static void main(String[] args) throws IOException {
String fileName = "example.txt";
String zipFile = "archive.zip";

// Создаём файл для сжатия
try (FileWriter writer = new FileWriter(fileName)) {
writer.write("Привет, это файл для архивации!");
}

// Запись в ZIP
try (FileOutputStream fos = new FileOutputStream(zipFile);
ZipOutputStream zos = new ZipOutputStream(fos);
FileInputStream fis = new FileInputStream(fileName)) {

ZipEntry entry = new ZipEntry(fileName);
zos.putNextEntry(entry);

byte[] buffer = new byte[1024];
int length;
while ((length = fis.read(buffer)) > 0) {
zos.write(buffer, 0, length);
}
}

System.out.println("Файл заархивирован в " + zipFile);
}
}


🚩Deflater/Inflater (общая компрессия без формата)

DeflaterOutputStream – сжимает данные без специфического формата.
InflaterInputStream – разжимает такие данные.
import java.io.*;
import java.util.zip.*;

public class DeflaterExample {
public static void main(String[] args) throws IOException {
String text = "Данные для сжатия";

// Сжатие
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
try (DeflaterOutputStream dos = new DeflaterOutputStream(byteStream)) {
dos.write(text.getBytes());
}
byte[] compressedData = byteStream.toByteArray();

// Разжатие
ByteArrayInputStream inputStream = new ByteArrayInputStream(compressedData);
try (InflaterInputStream iis = new InflaterInputStream(inputStream);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
byte[] buffer = new byte[1024];
int length;
while ((length = iis.read(buffer)) > 0) {
outputStream.write(buffer, 0, length);
}
System.out.println("Разжатые данные: " + new String(outputStream.toByteArray()));
}
}
}


Ставь 👍 и забирай 📚 Базу знаний
👍3
🤔 Какие варианты обработки исключений есть?

Можно использовать try-catch для локальной обработки ошибки и восстановления логики выполнения. Также можно применить throws, чтобы пробросить исключение выше по стеку вызовов. Дополнительно используют finally или try-with-resources, чтобы закрывать ресурсы. В крупных приложениях часто применяют централизованную обработку ошибок и логирование.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
👍3
🤔 Расскажи про процесс от пуша кода до продакшена

Когда разработчик пушит код, он проходит несколько этапов перед развертыванием в продакшене. Этот процесс автоматизируется с помощью CI/CD (Continuous Integration / Continuous Deployment).

🚩Этапы CI/CD

🟠Разработчик пушит код в Git-репозиторий
- Код отправляется в GitHub, GitLab, Bitbucket или другой репозиторий.
- Открывается Pull Request (PR) для ревью.
git add .
git commit -m "Добавлена новая фича"
git push origin feature-branch


🟠CI (Continuous Integration) – Автоматическая сборка и тестирование
После пуша CI-сервер (Jenkins, GitHub Actions, GitLab CI/CD, CircleCI)** запускает автоматические тесты и сборку.
Клонирование репозитория.
Сборка проекта (например, mvn package для Java).
Запуск юнит-тестов (JUnit, Mockito).
Запуск интеграционных тестов (например, TestContainers).
Анализ кода (SonarQube).
name: CI Pipeline

on:
push:
branches:
- main
- develop

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Setup Java
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'

- name: Build project
run: mvn clean package

- name: Run tests
run: mvn test


🟠CD (Continuous Deployment) – Развёртывание на Staging
После успешного CI код автоматически разворачивается в стейджинг (staging) – это тестовая среда, похожая на продакшен.
Развёртывание может происходить с помощью:
Docker + Kubernetes (K8s)
AWS CodeDeploy, GitLab CD
Terraform + Ansible
FROM openjdk:17
COPY target/app.jar /app.jar
CMD ["java", "-jar", "/app.jar"]


🟠Код проходит код-ревью и одобряется
Проверяется чистота кода, читаемость и ошибки.
В некоторых компаниях код проходит Security Review
git merge feature-branch
git push origin main


🟠CD (Continuous Deployment) – Развёртывание в продакшен
Blue-Green Deployment – новый код разворачивается на отдельном сервере, затем трафик переключается.
Canary Release – новый код деплоится на 5-10% пользователей, если всё хорошо – на всех.
Rolling Deployment – обновление происходит поэтапно, без даунтайма.
deploy:
stage: deploy
script:
- kubectl apply -f deployment.yaml
only:
- main


Ставь 👍 и забирай 📚 Базу знаний
👍1
🤔 Как создать свою аннотацию?

1. Используйте @interface для создания аннотации.
2. Определите параметры внутри аннотации (например, String value()).
3. Пример:
@MyAnnotation(value = "Example").
4. Аннотации могут быть применены к разным элементам (методам, классам) с помощью мета-аннотаций, таких как
@Target и @Retention.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
👍4🔥3
🤔 Чем отличается обычный объект от Bean?

В Spring термин Bean (бин) означает объект, управляемый Spring-контейнером.

🟠Обычный объект (Java POJO)
Создаётся вручную, Spring о нём ничего не знает
class Car {
void drive() {
System.out.println("Машина едет...");
}
}

public class Main {
public static void main(String[] args) {
Car car = new Car(); // Создаём объект вручную
car.drive();
}
}


🟠Spring Bean (управляемый объект)
Spring создаёт и управляет бином через аннотации.
import org.springframework.stereotype.Component;

@Component // Сообщает Spring, что этот класс - Bean
class Car {
void drive() {
System.out.println("Spring-машина едет...");
}
}


Теперь объект создаётся Spring-контейнером
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
Car car = context.getBean(Car.class); // Получаем Bean из Spring-контейнера
car.drive();
}
}


Ставь 👍 и забирай 📚 Базу знаний
👍4
🤔 Для чего нужны Function<T, R>, DoubleFunction<R>, IntFunction<R>, LongFunction<R>?

Для преобразования значения:
- принимают один аргумент;
- возвращают результат другого (или того же) типа.
Используются, например, при map, transform, compute.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
👍2
🤔 Расскажи про способы оптимизации запросов в БД

Оптимизация запросов в базе данных (БД) — это процесс улучшения их производительности, чтобы они выполнялись быстрее и использовали меньше ресурсов. Рассмотрим основные способы оптимизации SQL-запросов.

🟠Индексы
Индексы ускоряют поиск данных, создавая структуру, похожую на оглавление книги. Вместо полного перебора таблицы (Full Table Scan), БД быстро находит нужные строки по индексу.
CREATE INDEX idx_user_name ON users(name);


🟠Оптимизация `SELECT`
Избегайте SELECT *, так как это нагружает систему избыточными данными.
Плохо
SELECT * FROM users;


Хорошо
SELECT id, name FROM users;


🟠Использование `EXPLAIN`
Перед оптимизацией полезно посмотреть, как БД выполняет запрос.
EXPLAIN SELECT * FROM users WHERE name = 'Ivan';


🟠Ограничение выборки (`LIMIT`, `OFFSET`)
Если вам нужно получить только первые N строк, используйте LIMIT, чтобы БД не грузила лишние данные.
SELECT * FROM users ORDER BY id LIMIT 10;


🟠Оптимизация `JOIN`
Соединение (JOIN) таблиц может быть дорогостоящим. Вот несколько рекомендаций:
- Используйте индексы на полях, участвующих в JOIN.
- Если возможно, замените сложные JOIN на подзапросы (EXISTS, IN).
CREATE INDEX idx_orders_user_id ON orders(user_id);


🟠Кеширование запросов
Часто повторяющиеся запросы можно кэшировать на уровне БД (QUERY CACHE в MySQL) или в приложении (Redis, Memcached).
SET GLOBAL query_cache_size = 1000000;


🟠Нормализация и денормализация
Нормализация уменьшает дублирование данных, разбивая таблицы.
Денормализация может ускорить работу, дублируя данные и уменьшая количество JOIN.

Ставь 👍 и забирай 📚 Базу знаний
👍4