Bir müşteri projesi üzerinde çalışmaya başladığımda, çok sayıda sensör ölçümünü yöneten bir Filament Kaynağıyla karşılaştım. Tablo, yıllar boyunca toplanmış tarihsel veriler içeriyordu. Çoğu kullanıcı genellikle mevcut aya odaklanırken, bazen özel durumlar için eski ölçümleri gözden geçirmek de gerekebiliyordu.
İlk başta, kaynağın yavaş olduğu görünüyordu, ancak profil oluşturma işlemi daha derin bir sorunu ortaya çıkardı. Filament’in kendisinin darboğaz olmadığı, veritabanının problemin kaynağı olduğu anlaşıldı.
Sorunun Belirlenmesi
Sorunun Belirlenmesi
Tarih veya sensör türüne göre filtreleme birkaç saniye alıyordu bile, bu sadece mevcut ay için. Sıralama ve sayfalama oldukça yavaştı. Bu, klasik bir “her şey çalışıyor ama üretim için yeterince hızlı değil” durumuydu.
Amacım basitti: mevcut verilere hızlı erişim sağlarken, tarihsel sorgulamaların mümkün olmasını sağlamak ve paneli yeniden yazmaktan kaçınmak.
Aşağıdaki örnek, açıklık sağlamak için basitleştirilmiştir. Gerçek projede ilave filtreler ve performans optimizasyonları uygulanmıştır. Varsayılan tarihler mevcut aya odaklanıyor ama eski veri sorgulamaları tamamen destekleniyor. Proje FilamentPHP ve PostgreSQL ile inşa edilmiştir.
Tabloyu Ay Bazında Parçalama
Tabloyu Ay Bazında Parçalama
Problemi çözmek için, verileri aylara göre ayıran PostgreSQL tablo parçalamayı kullandım. İşte basitleştirilmiş bir örnek:
// Parent table
CREATE TABLE sensor_measurements (
id BIGSERIAL NOT NULL,
sensor_id BIGINT NOT NULL REFERENCES sensors(id) ON DELETE CASCADE,
value NUMERIC(10,2) NOT NULL,
measured_at TIMESTAMP(0) NOT NULL,
data JSONB,
created_at TIMESTAMP(0) DEFAULT now(),
updated_at TIMESTAMP(0) DEFAULT now(),
PRIMARY KEY (id, measured_at)
) PARTITION BY RANGE (measured_at);
// a month partition
CREATE TABLE IF NOT EXISTS sensor_measurements_2026_01 PARTITION OF sensor_measurements
FOR VALUES FROM ('2026-01-01') TO ('2026-02-01');
CREATE TABLE IF NOT EXISTS sensor_measurements_2026_02 PARTITION OF sensor_measurements
FOR VALUES FROM ('2026-02-01') TO ('2026-03-01');
Parça anahtarı birincil anahtar içinde olmalıdır.
Parçalama, mevcut ay için sorguların sadece küçük, ilgili bir alt kümesi taramasını sağlar ve performansı yüksek tutar. Tarihsel sorgular ise eski parçaları hedef alarak verimli bir şekilde çalışır.
Yeni yıl/ay parçalarının otomatik olarak oluşturulması için zamanlanmış bir iş oluşturdum. PostgreSQL parçalama hakkında daha fazla bilgi resmi PostgreSQL belgelerinde bulunabilir.
İndeks Eklemek ve Sorguları Optimize Etmek
İndeks Eklemek ve Sorguları Optimize Etmek
Her parçaya indeks oluşturulması gerekir, ana tabloda değil. Örneğin:
CREATE INDEX idx_sensor_measurements_2026_01_data_gin
ON sensor_measurements_2026_01(sensor_id)
USING GIN (data);
CREATE INDEX idx_sensor_measurements_2026_01_measured_at
ON sensor_measurements_2026_01(measured_at)
USING GIN (data);
Bu, filtrelere rağmen veritabanının ilgili satırları hızlı bir şekilde bulmasını sağlar.
Filament Kaynağını Ayarlamak
Filament Kaynağını Ayarlamak
Son olarak, Filament Kaynağını mevcut ay için varsayılan filtrelerle uyarladım:
use Carbon\Carbon;
class SensorMeasurementResource extends Resource
{
//...
public static function table(Table $table): Table
{
$now = Carbon::now();
return $table
->columns([
TextColumn::make('sensor_id')->sortable(),
TextColumn::make('value'),
TextColumn::make('measured_at')->dateTime(),
])
->filters([
Filter::make('date')
->form([
DatePicker::make('from')
->default($now->copy()->startOfMonth()),
DatePicker::make('to')
->default($now->copy()->endOfMonth()),
])
->query(fn(Builder $query, array $data) => $query
->when($data['from'], fn($q) => $q->where('measured_at', '>=', $data['from']))
->when($data['to'], fn($q) => $q->where('measured_at', 'Bu örnekte, TableSchema dosyasını basitlik için dahil etmedim. Bir sınırlama, filtrelerin zorunlu hale getirilemeyecek olmasıdır; bu da kullanıcıların bunu göstergeler araç çubuğundan kaldırmasına izin verir. Amaç, veritabanı yükünü optimize etmek için her zaman bir tarih aralığı bulundurmaktır.
Sonuçlar
Sonuçlar
Etki hemen hissedildi:
- Mevcut ay için sorgular artık 300ms'nin altında dönüyor.
- Tarihsel sorgular, ara sıra analiz için yeterince hızlı kalıyor.
- Kullanıcılar hem mevcut hem de geçmiş verileri zahmetsizce keşfedebiliyor.
Öğrenilen Dersler
Öğrenilen Dersler
- Filament büyük veri setlerini işleyebilir, eğer altındaki veritabanı optimize edilirse.
- Zaman dilimlerine göre parçalama, sensör veya tarihsel ölçüm verileri için idealdir.
- Doğru indeksler + sayfalama, büyük tabloların üretim ortamında kullanılabilir olmasını sağlar.
- Sorguları öncelikli olarak profil oluşturmak, admin panelinde kaybedilen saatleri kurtarır.
- Filament'teki küçük ayarlamalar (filtreler, tembel yükleme) kullanıcı deneyimini önemli ölçüde iyileştirebilir.
Kaynak: Orijinal Makale


