Ответ
Да, активно работал с индексами как в SQL (PostgreSQL), так и в NoSQL (MongoDB) базах данных в контексте Node.js приложений.
Для PostgreSQL с Node.js:
// Создание индексов через миграции Knex
exports.up = function(knex) {
return knex.schema.table('users', function(table) {
// Простой индекс
table.index('email');
// Составной индекс для частых запросов
table.index(['status', 'created_at']);
// Уникальный индекс
table.unique('username');
// Частичный индекс (только для активных пользователей)
knex.raw('CREATE INDEX idx_users_active ON users(id) WHERE status = 'active'');
});
};
Для MongoDB с Mongoose:
// Определение индексов в схеме
const userSchema = new mongoose.Schema({
email: { type: String, required: true },
companyId: { type: mongoose.Schema.Types.ObjectId },
createdAt: { type: Date, default: Date.now }
});
// Простой индекс
userSchema.index({ email: 1 });
// Составной индекс
userSchema.index({ companyId: 1, createdAt: -1 });
// TTL индекс для автоматического удаления старых записей
userSchema.index({ createdAt: 1 }, { expireAfterSeconds: 2592000 }); // 30 дней
Как я анализировал и оптимизировал индексы:
-
Использовал
EXPLAINв PostgreSQL:EXPLAIN ANALYZE SELECT * FROM orders WHERE user_id = 123 AND status = 'completed' ORDER BY created_at DESC; -
Мониторинг через pg_stat_user_indexes: Отслеживал, какие индексы реально используются
-
Практические правила, которые применял:
- Индексировал поля в
WHERE,JOIN,ORDER BY— особенно в часто выполняемых запросах - Использовал составные индексы для запросов с несколькими условиями, учитывая порядок полей
- Избегал избыточных индексов — удалял дублирующиеся или редко используемые
- Для текстового поиска использовал GIN/GIST индексы в PostgreSQL или text index в MongoDB
- Индексировал поля в
Пример проблемы и решения:
На одном проекте запрос поиска заказов по диапазону дат выполнялся 2+ секунды. Добавил индекс (user_id, created_at) и время уменьшилось до 50ms, так как PostgreSQL смог использовать индекс только для чтения (index-only scan).
Ответ 18+ 🔞
А, ну это про индексы, да? Ёпта, тема такая, что если не разбираться — можно на ровном месте такую производительность угробить, что потом волосы на жопе дыбом встанут. Я с этим делом в обеих вселенных работал — и в реляционной с PostgreSQL, и в документной с MongoDB, когда на Node.js всё это крутилось.
Вот как в PostgreSQL через Knex миграции это обычно выглядит:
// Создание индексов через миграции Knex
exports.up = function(knex) {
return knex.schema.table('users', function(table) {
// Простой индекс
table.index('email');
// Составной индекс для частых запросов
table.index(['status', 'created_at']);
// Уникальный индекс
table.unique('username');
// Частичный индекс (только для активных пользователей)
knex.raw('CREATE INDEX idx_users_active ON users(id) WHERE status = 'active'');
});
};
А в MongoDB с Mongoose вообще красота — прямо в схеме прописываешь:
// Определение индексов в схеме
const userSchema = new mongoose.Schema({
email: { type: String, required: true },
companyId: { type: mongoose.Schema.Types.ObjectId },
createdAt: { type: Date, default: Date.now }
});
// Простой индекс
userSchema.index({ email: 1 });
// Составной индекс
userSchema.index({ companyId: 1, createdAt: -1 });
// TTL индекс для автоматического удаления старых записей
userSchema.index({ createdAt: 1 }, { expireAfterSeconds: 2592000 }); // 30 дней
А теперь, блядь, самое интересное — как я эту всю магию анализировал и оптимизировал. Тут без подхода, как без рук — наткнёшься на проблему и будешь гадать, почему запрос тормозит, как будто на дворе 2002-й год.
-
EXPLAINв PostgreSQL — это святое, ебать мои старые костыли. Без него вообще никуда:EXPLAIN ANALYZE SELECT * FROM orders WHERE user_id = 123 AND status = 'completed' ORDER BY created_at DESC; -
Мониторинг через
pg_stat_user_indexes— чтобы понять, какие индексы реально пашут, а какие просто мусором лежат и память жрут. Удивление пиздец иногда наступает, когда видишь, что половина индексов ни разу не использовалась. -
Практические правила, которые в голове отложились:
- Индексируй то, что в
WHERE,JOIN,ORDER BYчасто мелькает — особенно в запросах, которые вызываются каждые пять секунд. Иначе будет тебе хиросима. - Составные индексы — твои лучшие друзья для запросов с кучей условий, но тут главное порядок полей не перепутать, а то будет манда с ушами вместо оптимизации.
- Избыточные индексы режь без жалости — зачем тебе три индекса, которые делают одно и то же? Это же просто место на диске и память впустую.
- Для текстового поиска — либо GIN/GIST в PostgreSQL, либо text index в MongoDB, иначе поиск будет работать, как хуй с горы катится.
- Индексируй то, что в
Был у меня один случай, просто пиздец. Запрос поиска заказов по диапазону дат выполнялся больше двух секунд — представляешь? Пользователи уже начинали бздеть от негодования. Добавил составной индекс (user_id, created_at), и, ёпта, время упало до 50 миллисекунд. Оказалось, PostgreSQL смог использовать индекс только для чтения, и всё полетело как по маслу. Вот так иногда одно правильное решение спасает от волнения ебать всего отдела.