Я решил посмотреть на производительность разных подходов для получения данных. Собственно, в статье хочу поделиться с вами результатами и опишу эти самые методы.
Задача.
Перед нами поставили следующую задачу - нужно найти компании определенной отрасли. Затем пройтись по всем этим компаниям и достать телефоны контактов, чтоб затем их обзвонить.
Первый метод. Решение в лоб или 1000 search
Придумываем алгоритм
- Добавляем контекстную переменную Компания
- С помощью этой переменной осуществляем поиск.
- Перебираем результат поиска.
- Для каждой компании проверяем контакты.
- Если контакты есть - получаем данные контакта с сервера
- Извлекаем телефоны контакта и складываем в специальный массив.
- Возвращаем массив
Приступаем к реализации и получаем вот такой код
Код:
const companySearch = Context.fields.company.app.search();
if (Context.data.industry) {
companySearch.where(it => it._industries.has(Context.data.industry!.id));
}
const companies = await companySearch.size(1000).all();
const phones: TPhone<PhoneType>[] = [];
for (let company of companies) {
const contactRef = company.data._contacts?.find(item => !!item.id);
if (contactRef && contactRef.id != EMPTY_UID) {
const contact = await contactRef.fetch();
if (contact && contact.data._phone && contact.data._phone.length > 0) {
phones!.push(...contact.data._phone);
}
}
}
Context.data.phones = phones;
Запускаем код, убеждаемся что он отрабатывает и возвращает записи.
Второй способ. Promise.All и 1000 фетчей
Используем тот же самый алгоритм, но вместо обычного for будем использовать Promise.all и map
Реализуем идею и получаем следующее решение
Код:
const companySearch = Context.fields.company.app.search();
if (Context.data.industry) {
companySearch.where(it => it._industries.has(Context.data.industry!.id))
}
const companies = await companySearch.size(1000).all();
const phones: TPhone<PhoneType>[] = [];
await Promise.all(companies.map(async (company) => {
const contactRef = company.data._contacts?.find(item => !!item.id);
if (contactRef && contactRef.id != EMPTY_UID) {
const contact = await contactRef.fetch();
if (contact && contact.data._phone && contact.data._phone.length > 0) {
phones!.push(...contact.data._phone);
}
}
}));
Context.data.phones = phones;
В целом, это решение уже быстрее, но количество запросов на сервер всё еще удручает.
Третий способ. Один search
Алгоритм
- Добавляем контекстную переменную Компания
- С помощью этой переменной осуществляем поиск.
- Добавляем контекстную переменную Контакт
- С помощью этой переменной создаем поиск на основе полученных компаний.
- Сохраняем результат в локальный массив
- Перебираем список компаний
- Для каждой компании проверяем контакты.
- Если контакты есть - получаем данные контакта из сохраненного массива
- Извлекаем телефоны контакта и складываем в специальный массив.
- Возвращаем массив
Приступаем к реализации и получаем вот такой код
Код:
const companySearch = Context.fields.company.app.search();
if (Context.data.industry) {
companySearch.where(it => it._industries.has(Context.data.industry!.id))
}
const companies = await companySearch.size(1000).all();
const contacts = await Context.fields.contact.app.search()
.where(x => x.__deletedAt.eq(null) && x._companies.link(companies))
.size(10000)
.all();
const phones: TPhone<PhoneType>[] = [];
for (let company of companies) {
const contactRef = company.data._contacts?.find(item => !!item.id);
if (contactRef && contactRef.id != EMPTY_UID) {
const contact = contacts.find(item => item.id === contactRef.id);
if (contact && contact.data._phone && contact.data._phone.length > 0) {
phones!.push(...contact.data._phone);
}
}
}
Context.data.phones = phones;
Не уверен, что здесь сильно прибавили в скорости, но точно снизили загрузку на сервер, так как в данном примере отправляем только 2 запроса на сервере.
Четвертый способ. Серверный search
Этот способ я реализовал только для того, чтоб сравнить скорость клиентского и серверного сценария.
Суть способа - берем код из третьего способа, переносим на Сервер и вызываем его из клиентского.
Испытания
Для испытаний создал через процесс компании и контакты и рандомно заполнил их данными.
Для испытаний немного доработал код (полный файл сценария будет в приложении).
Для расчета времени я использовал 10 успешных выполнений.
Результаты испытаний
Вывод
Проверяйте свои гипотезы и делитесь свои способами по улучшению производительности.
Ну и используйте search там, где это подходит.
Если у вас остались вопросы - пишите комментарии.
З.Ы. В архиве - клиентский сценарий, серверный сценарий и скриншот контекста