Блог
Кар'єра
Вакансії Компанії
Навчання
Співбесіди Тестування Відео
Екосистема
Пакети Ресурси
Інше
Події Про нас
Tips 06 березня 2026

value() vs first() - економія пам'яті

Потрібна тільки одна колонка з одного рядка? Не треба завантажувати всю модель.

first() створює повну Eloquent модель. value() повертає тільки дані.

Різниця:

  • first() повертає екземпляр моделі з усіма атрибутами
  • value() повертає одне скалярне значення
  • pluck() повертає колекцію значень з кількох рядків

Коли що використовувати:

Використовувати value() для однієї колонки, одного рядка. Використовувати pluck() для однієї колонки, кількох рядків. Використовувати first() тільки коли потрібні методи моделі.

Порада: На великих таблицях з багатьма колонками value() значно швидший.

// ПОГАНО: Завантажує повну модель з усіма колонками
$email = User::where('id', 1)->first()->email;

// ДОБРЕ: Повертає тільки рядок email
$email = User::where('id', 1)->value('email');

// Декілька рядків, одна колонка
$emails = User::where('active', true)->pluck('email');
// Повертає: Collection ['john@ex.com', 'jane@ex.com']

// Потрібні декілька колонок з кількох рядків?
$users = User::select('id', 'email')->get();

// З ключем за ID
$emails = User::pluck('email', 'id');
// Повертає: [1 => 'john@ex.com', 2 => 'jane@ex.com']

Коментарі

Увійдіть, щоб залишити коментар

Будьте першим, хто залишить коментар!

Інші поради

Tips 10 квітня 2026

sole() - суворе отримання одного результату

Запит має повернути рівно один запис. Повертає нуль або декілька? Це баг.

first() мовчки повертає null. sole() кидає виняток якщо не рівно один.

Коли використовувати:

  • Отримання за унікальним ідентифікатором
  • Коли декілька результатів вказують на пошкодження даних
  • Критична бізнес-логіка

Винятки що кидаються:

  • RecordsNotFoundException - нуль результатів
  • MultipleRecordsFoundException - більше одного

Порада: Використовувати у фінансових операціях де очікується рівно один запис.

// ПОГАНО: Мовчки повертає null або перший з багатьох
$user = User::where('email', $email)->first();
// Що якщо є дублікати? Мовчазний баг.

// ДОБРЕ: Гарантує рівно один результат
try {
    $user = User::where('email', $email)->sole();
    // Гарантовано єдиний користувач що підходить
} catch (RecordsNotFoundException $e) {
    // Користувач не знайдений
} catch (MultipleRecordsFoundException $e) {
    // Пошкодження даних - існують дублікати
}

// В обробці рахунків
$invoice = Invoice::where('invoice_number', $number)->sole();
// Дублікати були б серйозним багом

// firstOr vs soleOr
$user = User::where('email', $email)->soleOr(function () {
    throw new UserNotFoundException();
});

// Зі зв'язками
$user = User::with('profile')->where('id', $id)->sole();
Tips 04 квітня 2026

cursor() - потокове передавання великих наборів даних

При експорті 100,000 користувачів. get() завантажує все в пам'ять. Сервер падає.

cursor() передає результати один за одним. Константне використання пам'яті.

Як це працює:

Використовує MySQL cursor. Отримує один запис за раз. Пам'ять залишається низькою.

Коли використовувати:

  • Експорт великих наборів даних
  • Обробка величезних таблиць
  • Середовища з обмеженою пам'яттю

Компроміс:

Тримає з'єднання з базою даних відкритим довше. Не для веб-запитів, ідеально для команд.

Порада: Використовувати в консольних командах та jobs, уникай в HTTP контролерах.

// ПОГАНО: Завантажує 100k записів в пам'ять
$users = User::all(); // Може впасти
foreach ($users as $user) {
    $this->export($user);
}

// ДОБРЕ: Потокове передавання один за одним
foreach (User::cursor() as $user) {
    $this->export($user); // Константна пам'ять
}

// В консольній команді
public function handle()
{
    $this->output->progressStart(User::count());

    foreach (User::cursor() as $user) {
        $this->processUser($user);
        $this->output->progressAdvance();
    }

    $this->output->progressFinish();
}

// З умовами
foreach (User::where('active', true)->cursor() as $user) {
    // Обробляти тільки активних користувачів
}
Tips 31 березня 2026

exists() vs count() - розумна перевірка

Перевірка чи користувач має пости? Використання $user->posts->count() > 0 завантажує всі пости.

exists() зупиняється на першому збігу. Набагато швидше.

Різниця:

  • count() підраховує всі записи
  • exists() зупиняється коли знаходить перший

Вплив на продуктивність:

З 10,000 постів - count() завантажує всі, exists() знаходить один і зупиняється.

Порада: Використання exists() для булевих перевірок, count() тільки коли потрібне фактичне число.

// ПОГАНО: Завантажує всі пости, рахує їх
if ($user->posts->count() > 0) {
    echo "Користувач має пости";
}

// ДОБРЕ: Зупиняється на першому пості
if ($user->posts()->exists()) {
    echo "Користувач має пости";
}

// Перевірка чи зв'язок порожній
if ($user->posts()->doesntExist()) {
    echo "Пости не знайдено";
}

// Рівень запиту
if (Post::where('published', true)->exists()) {
    // Принаймні один опублікований пост існує
}

// Коли справді потрібна кількість
$postCount = $user->posts()->count();
echo "Користувач має {$postCount} постів";

// Перевірка порожнього на завантаженому зв'язку
if ($user->posts->isEmpty()) {
    // Вже завантажено, без додаткових запитів
}
Tips 27 березня 2026

whereIn() з великими масивами - пастка пам'яті

Передавання 10,000 ID в whereIn()? Рядок запиту стає величезним.

MySQL має ліміти розміру запиту. PHP використовує тонни пам'яті.

Кращий підхід:

Використовувати підзапит або тимчасову таблицю для великих наборів даних.

Продуктивність:

  • whereIn() з 100 елементами - нормально
  • whereIn() з 10,000 елементами - проблема
  • Підзапит - константна пам'ять

Порада: Якщо масив має більше 1000 елементів, розглянь використання підзапиту або chunking.

// ПОГАНО: Великий масив в whereIn
$userIds = range(1, 10000); // 10k ID
$users = User::whereIn('id', $userIds)->get();
// Величезний запит, високе використання пам'яті

// ДОБРЕ: Використовувати підзапит
$activeUserIds = DB::table('user_activity')
    ->where('last_login', '>', now()->subDays(30))
    ->select('user_id');

$users = User::whereIn('id', $activeUserIds)->get();

// Альтернатива: Join
$users = User::join('user_activity', 'users.id', '=',
    'user_activity.user_id')
    ->where('user_activity.last_login', '>', now()->subDays(30))
    ->select('users.*')
    ->get();

// Розділяй великі операції
$userIds = range(1, 10000);
collect($userIds)->chunk(500)->each(function ($chunk) {
    User::whereIn('id', $chunk)->update(['notified' => true]);
});
Tips 23 березня 2026

limit() - не завантажувати непотрібне

При завантаженні 50,000 записів для показу 10 на екрані.

Додаток зависає. Серверу бракує пам'яті. Користувач закриває браузер через 30 секунд.

Проблема:

Без limit(), Eloquent завантажує все в пам'ять. Пагінація допомагає, але все одно потрібен limit() в багатьох випадках.

Коли використовувати:

  • Попередні перегляди та зразки
  • Останні N елементів
  • Топ виконавці
  • Будь-який сценарій "показати перші декілька"

Порада: Поєднуй з orderBy() для консистентних результатів. Без сортування limit() повертає випадкову підмножину.

// ПОГАНО: Завантажує все
$products = Product::where('active', true)->get();
// Повертає 50,000 продуктів в пам'яті

// ДОБРЕ: Тільки те що потрібно
$featured = Product::where('featured', true)
    ->orderBy('created_at', 'desc')
    ->limit(5)
    ->get();

// Останні 10 замовлень
$recent = Order::latest()->limit(10)->get();

// Топ 3 користувачі за балами
$leaders = User::orderBy('points', 'desc')->limit(3)->get();

// Попередній перегляд дашборду
$stats = [
    'recent_orders' => Order::latest()->limit(5)->get(),
    'top_products' => Product::orderBy('sales', 'desc')
        ->limit(10)->get(),
    'new_users' => User::latest()->limit(20)->get(),
];

// Без orderBy - непередбачувані результати
$random = Post::limit(5)->get(); // ПОГАНО
$latest = Post::latest()->limit(5)->get(); // ДОБРЕ
Завантаження...