Laravel to jeden z najpopularniejszych frameworków PHP, a jego ORM – Eloquent – znacznie upraszcza operacje na bazie danych. Jednak przy dużych zbiorach danych (miliony rekordów) zapytania stają się coraz wolniejsze.
Rozwiązanie? Partycjonowanie danych!
Partycjonowanie pozwala na podział dużej tabeli na mniejsze sekcje (partycje), co zwiększa wydajność i ułatwia zarządzanie danymi. Laravel domyślnie nie wspiera partycjonowania, ale możemy wykorzystać bibliotekę laravel-partition, która pozwala na łatwą implementację tej techniki.
Jak działa partycjonowanie w bazach danych?
Korzyści partycjonowania:
- Szybsze zapytania – skanowana jest tylko wybrana partycja zamiast całej tabeli.
- Łatwiejsze zarządzanie danymi – można usunąć całą partycję zamiast pojedynczych rekordów.
- Lepsza wydajność indeksów – indeksy w mniejszych tabelach działają szybciej.
- Możliwość równoważenia obciążenia – w niektórych bazach można przechowywać partycje na różnych serwerach.
Partycjonowanie w Laravel przy użyciu
Aby dodać bibliotekę laravel-partition do projektu Laravel, wykonaj:
composer require jbernard/laravel-partition
Po instalacji można opublikować plik konfiguracyjny:
php artisan vendor:publish --provider="Jbernard\LaravelPartition\PartitionServiceProvider"
To utworzy plik config/partition.php, w którym można dostosować ustawienia partycjonowania.
Tworzenie partycji na poziomie bazy danych (MySQL)
Załóżmy, że mamy tabelę orders, którą chcemy podzielić na partycje według roku zamówienia (order_date).
Definiowanie modelu z partycjonowaniem
use Jbernard\LaravelPartition\Partitionable;
use Illuminate\Database\Eloquent\Model;
class Order extends Model
{
use Partitionable;
protected $table = 'orders';
protected $fillable = ['customer_id', 'order_date', 'total_amount'];
public static function getPartitionColumn(): string
{
return 'order_date'; // Klucz partycjonowania
}
public static function getPartitionStrategy(): string
{
return 'range'; // Typ partycjonowania
}
public static function getPartitionRanges(): array
{
return [
'p2022' => ['min' => '2022-01-01', 'max' => '2022-12-31'],
'p2023' => ['min' => '2023-01-01', 'max' => '2023-12-31'],
'p2024' => ['min' => '2024-01-01', 'max' => '2024-12-31'],
];
}
}
Analiza kodu
use Partitionable– użycie traitaPartitionabledodaje wsparcie dla partycjonowania w Eloquent.getPartitionColumn()– definiuje, na jakiej kolumnie opiera się partycjonowanie (order_date).getPartitionStrategy()– określa, że partycjonowanie odbywa się według zakresu (range).getPartitionRanges()– tworzy zakresy dla lat 2022-2024.
Tworzenie migracji dla partycji w MySQL
Schema::create('orders', function (Blueprint $table) {
$table->id();
$table->integer('customer_id');
$table->date('order_date');
$table->decimal('total_amount', 10, 2);
$table->timestamps();
})->partitionByRange('order_date', [
'p2022' => ['min' => '2022-01-01', 'max' => '2022-12-31'],
'p2023' => ['min' => '2023-01-01', 'max' => '2023-12-31'],
]);
Analiza kodu
- Tworzy tabelę
ordersz kluczamiorder_date, które są podstawą podziału na partycje. - Metoda
partitionByRange()automatycznie dodaje partycjonowanie w MySQL. - Dane będą zapisywane do odpowiednich partycji na podstawie
order_date.
Pobieranie danych z wykorzystaniem partycji w Laravel
$orders = Order::whereYear('order_date', 2023)->get();
MySQL automatycznie wybierze odpowiednią partycję (p2023).
Jeśli chcemy wymusić konkretną partycję, możemy użyć surowego zapytania SQL:
$orders = DB::select(DB::raw("SELECT * FROM orders PARTITION (p2023) WHERE order_date >= '2023-01-01'"));
Partycjonowanie na poziomie aplikacji (Dynamiczne Tabele w Laravel)
Zamiast używać partycjonowania na poziomie bazy, możemy tworzyć osobne tabele dla każdego roku.
Dynamiczne zmienianie tabeli w Eloquent
class OrderPartition extends Model
{
protected $table;
public function __construct($year)
{
$this->table = 'orders_' . $year;
}
}
Teraz model może dynamicznie przełączać tabelę w zależności od potrzeb.
Tworzenie nowej tabeli (partycji) w Laravel
DB::statement("
CREATE TABLE orders_2025 LIKE orders_2024
");
Tworzy nową tabelę orders_2025, kopiując strukturę orders_2024.
Pobieranie danych z określonej partycji
$orders = (new OrderPartition(2023))->where('customer_id', 1)->get();
Dane pobierane są tylko z tabeli orders_2023, co znacząco przyspiesza działanie.
Kiedy warto używać partycjonowania?
Warto stosować partycjonowanie, jeśli:
- Tabela zawiera miliony rekordów, co powoduje spadek wydajności.
- Większość zapytań dotyczy określonego zakresu danych (np. roku).
- Często usuwasz stare dane – można łatwo usunąć całą partycję zamiast pojedynczych rekordów.
Nie warto, jeśli:
- Dane są małe (poniżej kilku milionów rekordów).
- Zapytania wymagają częstego łączenia partycji (
JOIN), co może być wolne.
Podsumowanie
- Laravel nie wspiera partycjonowania natywnie, ale biblioteka
laravel-partitionznacznie ułatwia wdrożenie. - Możemy użyć partycjonowania na poziomie bazy (MySQL/PostgreSQL) lub partycjonowania na poziomie aplikacji (dynamiczne tabele w Laravel).
laravel-partitionautomatycznie zarządza partycjami, co upraszcza cały proces.
Czy Twoja aplikacja obsługuje miliony zamówień? Jeśli tak, partycjonowanie może znacząco przyspieszyć Laravel i zmniejszyć obciążenie bazy danych!