Почему поиск без индекса быстрее поиска с индексом?



@Eugene_Evgeni

Очень странная ситуация.
Я решил «поиграть» с базой данных и создал БД с 20 000 000 записей и провёл пару тестов. По идеи, запись с индексом должна быть дольше, а поиск элементов быстрее. Тесты были такие:

Вопросы тестирования

заполнение БД;
добавление 100 элементов;
получение 100 000 элемента;
получение 20 000 000 элемента;
получение элементов в котором встречается число 2555;

Сейчас я приведу пример своего кода на nest js, но он лишь обёртка, так что под ним я ещё и запишу команды ( SQL-запросы). Так же я в обоих случаях заполнял БД одинаково без nestjs ( смотрите в SQL-запросах). Тесты в обоих случаях одинаковые, сравниваю по индексу key ( само поле chatKey ).

Вот код на nestjs:

spoiler

модель

@Table({tableName: ‘chats’, createdAt: false, updatedAt: false})
export class MessageTable extends Model {

@Column({type: DataType.INTEGER, primaryKey: true, unique: true, autoIncrement: true})
id: number;

@Column({type: DataType.JSON})
members: number[];

@Index(‘key’)
@Column({type: DataType.TEXT})
chatKey: string;

@Column({type: DataType.INTEGER})
author: number;

@Column({type: DataType.STRING(32)})
date: string;

@Column({type: DataType.STRING(255)})
data: string;

@Column({type: DataType.STRING(511)})
files: string;

}

тесты

addMessage = (number: number) => {
return new Promise( (res) => {
this.ChatRepository.create({
id: 20000000 + number,
author: number,
date: ‘asd’,
chatKey: (20000000 + number).toString(),
data: ‘das’,
files: ‘[]’,
members: [1]
}).then( () => {return res(‘das’)});
})
}

getMessageByKey = (number) => {
return new Promise( (res) => {
this.ChatRepository.findAll({where: {chatKey: number.toString()} } )
.then( (response) => res(response))
})
}

getMessagesByKey = (number) => {
return new Promise( (res) => {
this.ChatRepository.findAll({where: {
chatKey: {
[Op.like]: `%${number.toString()}%`
}
} } )
.then( (response) => res(response))
})
}
for (let indexx = 0; indexx < 100; indexx++) {
this.messageService.addMessage(indexx + 3)
.then( () => {if (indexx === 99) {
console.log(‘Ready by ‘ + (Date.now() — this.DateNow) );
} })
}
this.messageService.getMessageByKey(100000).then( (res) => {
console.log(res);
console.log(‘Ready by ‘ + (Date.now() — this.DateNow));
})

this.messageService.getMessageByKey(20000000).then( (res) => {
console.log(res);
console.log(‘Ready by ‘ + (Date.now() — this.DateNow));
})

this.messageService.getMessagesByKey(2555).then( () => {
console.log(‘Ready by ‘ + (Date.now() — this.DateNow));
})

SQL-запросы

INSERT INTO chats(author, «chatKey», «data», date, files, id, members)
SELECT 1, s.id ‘»asd»‘, ‘»asdasd»‘, ‘»[asdfasdf]»‘, s.id, ‘[12, 13]’
FROM generate_series(1, 20000000) as s(ID)
ORDER BY random()

Executing (default): INSERT INTO «chats» («id»,»members»,»chatKey»,»author»,»date»,»data»,»files») VALUES ($1,$2,$3,$4,$5,$6,$7) RETURNING «id»,»members»,»chatKey»,»author»,»date»,»data»,»files»;

Executing (default): SELECT «id», «members», «chatKey», «author», «date», «data», «files» FROM «chats» AS «MessageTable» WHERE «MessageTable».»chatKey» = ‘100000’;

Executing (default): SELECT «id», «members», «chatKey», «author», «date», «data», «files» FROM «chats» AS «MessageTable» WHERE «MessageTable».»chatKey» = ‘20000000’;

Executing (default): SELECT «id», «members», «chatKey», «author», «date», «data», «files» FROM «chats» AS «MessageTable» WHERE «MessageTable».»chatKey» LIKE ‘%2555%’;

А теперь самое интересное. Я тестил в два дня, так как создание с индексами заняло больше времени, чем я думал, поэтому я в первом случае проводил 5 тестов и усреднял значения, в в тесте с индексами писал разброс.

creating without index — 11 min 18 sec
adds 100 elements without index — 7803
get 100 000 element without index — 942
get 20 000 000 element without index — 5478
get all element where key === 2555 without index — 1195 — 6141

creating — 2 hr 16 min.
adds 100 elements — 5206 — 58907
get 100 000 element — 3813 — 56000
get 20 000 000 element — 1922 — 7316
get all element where key === 2555 — 2847 — 32458

Почему-то в среднем поиск без индекса быстрее, чем с ним. У меня два вопроса. Первый, что я сделал не так? Второй, стоит ли в этом случае использовать индексы?


Решения вопроса 2



@Fragster

Сделайте explain analyze и посмотрите. Опционально запихайте на
https://explain.tensor.ru/

Скорее всего дело в том, что «MessageTable».»chatKey» LIKE ‘%2555%’ в принципе не может использовать индексы (по своей природе), а операций чтения нужно намного больше. Ну и записи при вставке.

Кстати, иногда эффективнее удалить индексы, вставить данные, добавить индексы, но это не всегда возможно. Да и не всегда эффективнее кроме, разве что, случая обновления бОльшей части таблицы, нужно проверять.


Ответы на вопрос 0

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *