JavaRush /Курсы /Модуль 4: FastAPI /Оптимизация запросов в гибридных архитектурах

Оптимизация запросов в гибридных архитектурах

Модуль 4: FastAPI
10 уровень , 8 лекция
Открыта

Представьте, что вы строите крутой интернет-магазин. У вас есть SQL-база для управления заказами и складом, а NoSQL-база отвечает за рекомендации товаров. Все работает, как часы, пока на ваш сайт не приходит толпа покупателей в Черную пятницу. Ваши данные начинают обрабатываться медленно, пользователи злятся, а руководство паникует. Тут-то вы и понимаете: Оптимизация запросов – это не просто фан-сервис для программистов.

Оптимизация запросов позволяет:

  • Уменьшить нагрузку на серверы.
  • Сделать приложение быстрее (пользователи любят скорость!).
  • Сэкономить деньги на инфраструктуре.

В гибридных архитектурах, где мы взаимодействуем сразу с разными типами баз данных (SQL и NoSQL), задачи усложняются, но разобраться во всем вполне реально.


Основы оптимизации запросов

  1. Индексы: твои лучшие друзья.
    Индексы – это как скоростная трасса для запросов. Если правильно их настроить, сервер сможет находить нужные данные намного быстрее.

    Пример индекса в PostgreSQL:
    
    -- Создаем индекс на колонке "email" таблицы "users"
    CREATE INDEX idx_users_email ON users(email);
            
    Теперь запрос вроде SELECT * FROM users WHERE email = 'example@example.com'; будет выполняться гораздо быстрее.

    Пример индекса в MongoDB:
    
    # Создаем индекс на поле "user_id" в коллекции "orders"
    db.orders.create_index("user_id")
            

    Индексы можно и нужно использовать в обеих базах (SQL и NoSQL), но не переусердствуйте: слишком много индексов увеличивает время записи данных.

  2. Разделять и властвовать: горизонтальная и вертикальная партиция.
    Партиционирование данных — это разбиение больших таблиц (SQL) или коллекций (NoSQL) на части.

    Горизонтальное партиционирование:
    вы разделяете данные по строкам. Например, если у вас есть таблица пользователей с миллионами записей, можно разбить их на основе ID:
    • От 1 до 500 000 в одной таблице.
    • От 500 001 до 1 000 000 — в другой.
    
    CREATE TABLE users_1_to_500k PARTITION OF users FOR VALUES FROM (1) TO (500000);
            
    Вертикальное партиционирование:
    здесь вы делите данные по колонкам. Например, в таблице заказов можно выделить часто используемые поля (order_id, status) в одну таблицу, а редко используемые (delivery_notes, archive) — в другую.

    В MongoDB:
    в NoSQL подход немного отличается: партиции создаются на уровне шардирования. Для этого вы указываете ключ шардирования, например:
    
    sh.enableSharding("myDatabase")
    sh.shardCollection("myDatabase.orders", { "region": 1 })
            
    Теперь заказы автоматически распределяются по регионам.

Кэширование: почему бы не запомнить результаты?

Кэширование позволяет избежать частого обращения к базе данных. Например, данные, которые редко изменяются (каталог товаров или статистика), можно закэшировать.

Redis — отличный инструмент для промежуточного хранения данных. Мы можем кэшировать результаты из PostgreSQL и MongoDB.

Пример в FastAPI:


import redis
import json
from fastapi import FastAPI

app = FastAPI()
redis_client = redis.StrictRedis(host='localhost', port=6379, decode_responses=True)

@app.get("/product/{product_id}")
async def get_product(product_id: int):
    cached_product = redis_client.get(f"product:{product_id}")
    if cached_product:
        return json.loads(cached_product)
    
    # Если в кэше нет данных, идем в базу данных
    product = get_product_from_postgresql(product_id)
    redis_client.set(f"product:{product_id}", json.dumps(product), ex=3600)  # Кэшируем на час
    return product

Теперь мы существенно снижаем нагрузку на PostgreSQL!


Оптимизация запросов в гибридных системах: основы

  • Используйте только нужные данные.
    Не следует запрашивать больше данных, чем требуется. Например, вместо того чтобы делать:
    
    SELECT * FROM orders;
            
    Лучше явно указать нужные колонки:
    
    SELECT order_id, status FROM orders;
            
  • Асинхронные запросы для работы с MongoDB.
    Когда вы взаимодействуете с MongoDB через FastAPI, важно использовать асинхронные запросы для повышения производительности.
    Пример:
    
    from motor.motor_asyncio import AsyncIOMotorClient
    
    client = AsyncIOMotorClient('mongodb://localhost:27017')
    db = client.mydatabase
    
    async def get_orders_by_user(user_id):
        return await db.orders.find({"user_id": user_id}).to_list(length=100)
            

Агрегации и аналитика в гибридных системах

Если ваши данные находятся в разных базах, вам, скорее всего, понадобится их агрегировать для объединенного анализа. Как это выглядит?

В PostgreSQL используйте сложные запросы с группировкой:


SELECT user_id, COUNT(order_id) AS num_orders
FROM orders
GROUP BY user_id
HAVING COUNT(order_id) > 5;

В MongoDB используйте агрегации:


pipeline = [
    {"$match": {"status": "completed"}},
    {"$group": {"_id": "$user_id", "total": {"$sum": "$amount"}}}
]
results = db.orders.aggregate(pipeline)

Иногда вам нужно данные из обеих баз. Один из подходов — сначала собрать их отдельно, а затем объединить на уровне Python:


sql_results = get_data_from_postgresql()
nosql_results = get_data_from_mongodb()

combined_results = merge_results(sql_results, nosql_results)

Кэширование сложных запросов через ETL

Если у вас есть тяжелые запросы на уровне гибридной архитектуры, возможно, стоит использовать ETL (Extract, Transform, Load) процессы. Например, раз в день вытягивать данные из SQL и NoSQL в промежуточное хранилище (тот же Redis).

Пример:

  • На уровне PostgreSQL собираем ежедневные заказы:
    
    SELECT user_id, SUM(amount) as total_amount
    FROM orders
    WHERE order_date = CURRENT_DATE
    GROUP BY user_id;
            
  • Результаты записываем в Redis для быстрого доступа:
    
    redis_client.set("daily_orders", json.dumps(sql_results))
            

Лучшие практики работы с запросами в гибридной архитектуре

  1. Разделите ответственность. Пусть SQL обрабатывает транзакционные запросы, а NoSQL занимается аналитикой или хранением больших данных.
  2. Используйте кэширование на всех уровнях: запросов, результатов или даже на уровне приложений.
  3. Регулярно профилируйте ваши запросы, чтобы находить узкие места. Для PostgreSQL используйте EXPLAIN ANALYZE. Для MongoDB — профайлер запросов db.system.profile.
  4. Проверяйте индексы: они гибки, но требуют ресурсов при записи. Включайте только те, которые действительно нужны.

Теперь вы готовы сразиться с медленными запросами в любой гибридной системе. Помните: оптимизация — это не фокус, который вы делаете раз и навсегда. Это процесс, который следует повторять по мере роста вашего проекта.

1
Задача
Модуль 4: FastAPI, 10 уровень, 8 лекция
Недоступна
Кэширование запросов через Redis
Кэширование запросов через Redis
1
Задача
Модуль 4: FastAPI, 10 уровень, 8 лекция
Недоступна
Агрегация данных из PostgreSQL и MongoDB
Агрегация данных из PostgreSQL и MongoDB
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ