Sayfalama, sanallaştırma, akıllı filtreleme ve daha iyi sorgular kullanarak 100k satırlı dashboard listelerini nasıl hızlı tutacağınızı öğrenin, iç araçlar hızlı kalsın.

Bir liste ekranı genellikle iyi çalışır — ta ki çalışmaz hale gelene kadar. Kullanıcılar küçük duraksamalar fark etmeye başlar: kaydırma takılır, her güncellemeden sonra sayfa bir an donar, filtreler saniyeler alır ve her tıklamada bir yükleyici görünür. Bazen tarayıcı sekmesi donmuş gibi görünür çünkü UI iş parçacığı meşguldür.
100k satır yaygın bir eşiktir çünkü sistemin her parçasını aynı anda zorlar. Veri tabanı için hâlâ normal bir büyüklük olabilir, ama tarayıcıda ve ağda küçük verimsizlikleri görünür hale getirir. Her şeyi bir kerede göstermeye çalışırsanız, basit bir ekran ağır bir boru hattına dönüşür.
Ama amaç tüm satırları render etmek olmamalı. Amaç birinin ihtiyacını çabucak bulmasına yardımcı olmak: doğru 50 satır, bir sonraki sayfa veya filtreye göre daraltılmış bir dilim.
İşi dört parçaya ayırmak yardımcı olur:
Bu parçalardan herhangi biri pahalıysa, tüm ekran yavaş hissedilir. Basit bir arama kutusu 100k satırı sıralayan, binlerce kayıt döndüren ve sonra tarayıcıyı hepsini render etmeye zorlayan bir istek tetikleyebilir. Böylece yazma gecikir.
Takımlar dahili araçları hızla (Koder.ai gibi vibe-coding platformlarıyla) kurarken, liste ekranları genellikle gerçek veri büyümesiyle "demo veriyle çalışıyor" ile "her gün anında hissettiriyor" arasındaki farkı ortaya çıkarır.
Optimize etmeden önce bu ekran için hızlı olmanın ne anlama geldiğine karar verin. Birçok ekip her şeyi yüklemeyi (throughput) kovalar; oysa kullanıcıların çoğu düşük gecikme (low latency) ister: bir şeyin çabucak güncellenmesini görmek. Bir liste, tüm 100k satırı hiç yüklemese bile kaydırma, sıralama ve filtrelemelere hızlı cevap verdiği sürece anlık hissedilebilir.
Pratik bir hedef, tam yükleme süresi değil, ilk satıra ulaşma süresidir. Kullanıcılar ilk 20–50 satırı hızlı gördüklerinde sayfaya güvenir ve etkileşimler akıcı kalır.
Her değiştirmede takip edebileceğiniz küçük bir sayı seti seçin:
COUNT(*) ve geniş SELECTler)Bunlar yaygın semptomlara karşılık gelir. Kaydırırken tarayıcı CPU sıçrama yapıyorsa, frontend satır başına çok iş yapıyor demektir. Yükleyici bekliyorsa ama kaydırma sonra iyiyse, genellikle backend veya ağ problemidir. İstek hızlı ama sayfa hâlâ donuyorsa, neredeyse her zaman render ya da ağır istemci tarafı işlemdir.
Basit bir deney yapın: UI aynı kalsın, ama backend'i geçici olarak aynı filtrelerle sadece 20 satır dönecek şekilde sınırlayın. Hızlanıyorsa darboğaz yük boyutu veya sorgu süresidir. Hâlâ yavaşsa render, formatlama ve satır başına bileşenlere bakın.
Örnek: Dahili bir Orders ekranı yazarken arama yazarken yavaş hissediyor. API 5.000 satır döndürüyor ve tarayıcı her tuşa basmada bunları filtreliyorsa, yazma gecikir. API COUNT için 2 saniye alıyorsa ve filtrelenmemişse, herhangi bir satır değişmeden önce bekleme görürsünüz. Farklı düzeltmeler, aynı kullanıcı şikayeti.
Tarayıcı genellikle ilk darboğazdır. API hızlı olsa bile sayfa çok fazla boyamaya çalışıyorsa liste yavaş hissedilebilir. İlk kural basit: aynı anda binlerce satırı DOM'a render etmeyin.
Tam sanallaştırma eklemeden önce bile, her satırı hafif tutun. İç içe sarılmış sarmalayıcılar, ikonlar, tooltiplər ve her hücrede karmaşık koşullu stiller bulunan bir satır, kaydırma ve her güncellemede maliyetlidir. Düz metin, birkaç küçük rozet ve satır başına bir veya iki etkileşimli öğe tercih edin.
Sabit satır yüksekliği göründüğünden daha fazla yardımcı olur. Her satır aynı yüksekliğe sahip olduğunda tarayıcı düzeni tahmin edebilir ve kaydırma akıcı kalır. Değişken yüksekliğe sahip satırlar (satır kayması yapan açıklamalar, açılabilen notlar, büyük avatarlar) ekstra ölçüm ve yeniden akış tetikler. Ek detay gerekiyorsa, tam satır yerine yan panel veya tek bir açılabilir alan düşünün.
Formatlama da sessiz bir maliyettir. Tarihler, para birimleri ve ağır string işlemleri birçok hücrede tekrarlandığında birikir.
Bir değer görünür değilse, onu henüz hesaplamayın. Pahalı formatlama sonuçlarını önbelleğe alın ve örneğin bir satır görünür olduğunda veya kullanıcı satırı açtığında hesaplayın.
Hızlı bir geçişle sıklıkla fark yaratan adımlar:
Örnek: 12 sütunda para ve tarih formatlayan bir Invoices tablosu kaydırırken takılır. Fatura başına formatlanmış değerleri önbelleğe almak ve ekran dışı satırlar için işi ertelemek, derin backend çalışmalarına başlamadan önce bile anında hissettirir.
Sanallaştırma, tablo yalnızca gerçekten görebildiğiniz satırları (artı küçük tamponu) çizer. Kaydırdıkça aynı DOM öğelerini yeniden kullanır ve içlerindeki veriyi değiştirir. Bu, tarayıcının on binlerce satır bileşenini aynı anda boyamasını engeller.
Sanallaştırma, uzun listeler, geniş tablolar veya ağır satırlar (avatarlar, durum chipleri, işlem menüleri, tooltiplər) için uygundur. Kullanıcılar çok kaydırıp kesintisiz bir görünüm bekliyorsa da faydalıdır.
Bu sihir değildir. Bazı sürprizlere yol açan noktalar:
En basit yaklaşım sıkıcıdır: sabit satır yüksekliği, öngörülebilir sütunlar ve her satırda çok fazla etkileşimli widget olmaması.
İkisini birleştirebilirsiniz: sunucudan ne getirdiğinizi sınırlamak için sayfalama (veya cursor tabanlı “daha yükle”) kullanın, ve çekilen dilim içinde render'ı ucuz tutmak için sanallaştırma yapın.
Pratik bir desen: normal bir sayfa boyutu (genellikle 100–500 satır) çekin, o sayfa içinde sanallaştırın ve sayfalar arası gezinme için net kontroller sunun. Sonsuz kaydırma kullanıyorsanız, kullanıcıların her şeyi görmediklerini anlaması için "X yüklendi / Y" gibi bir gösterge ekleyin.
Veriler büyüdükçe kullanılabilir kalan bir liste ekranına ihtiyacınız varsa, sayfalama genellikle en güvenli varsayımdır. Öngörülebilir, yönetici iş akışlarına (inceleme, düzenleme, onay) iyi uyar ve "bu filtrelerle sayfa 3" gibi ihtiyaçlara sürpriz olmadan destek verir. Birçok ekip, daha şık kaydırma denedikten sonra tekrar sayfalamaya döner.
Sonsuz kaydırma rahat olabilir ama gizli maliyetleri vardır. İnsanlar nerede olduklarını kaybedebilir, geri butonu aynı noktaya dönmeyebilir ve uzun oturumlar daha fazla satır yüklendiği için bellek birikebilir. Orta yol olarak "Daha fazla yükle" düğmesi sayfalama kullanır ama kullanıcıyı yönlendirir.
Offset sayfalama klasik page=10&size=50 yaklaşımıdır. Basittir, ama büyük tablolarda veritabanının daha sonra sayfalara gitmek için birçok satırı atlaması gerektiğinden yavaşlayabilir. Ayrıca yeni satırlar geldiğinde öğeler sayfalar arasında kayabilir.
Keyset sayfalama (cursor olarak da anılır) "son görülen öğeden sonra sonraki 50 satır" ister; genelde id veya created_at değeri kullanılır. Atlama ve sayma işlemi daha az olduğu için performansı daha sabit kalır.
Pratik kural:
Kullanıcılar toplamları görmeyi sever ama eşleşen tüm satırları saymak (full count) ağır filtrelerde pahalı olabilir. Seçenekler: popüler filtreler için sayıları önbelleğe almak, sayfa yüklendikten sonra arka planda sayıyı güncellemek veya yaklaşık bir sayı göstermek (ör. "10.000+").
Örnek: Dahili bir Orders ekranı keyset sayfalama ile sonuçları anında gösterir, ardından kullanıcı filtreyi değiştirmeyi durdurduğunda tam toplamı doldurur.
Koder.ai ile inşa ediyorsanız, sayfalama ve sayaç davranışını ekran spesifikasyonunun başında ele alın, böylece üretilen backend sorguları ve UI durumu çakışmaz.
Çoğu liste ekranı yavaş hissedilir çünkü her şeyi açık bırakır: her şeyi yükleyip sonra kullanıcıyı daraltmasını beklersiniz. Bunu tersine çevirin. Kullanıcıya küçük, faydalı bir başlangıç sunun (ör. Son 7 gün, Benim öğelerim, Durum: Açık) ve "Tüm zamanlar" seçimini açık bir seçenek yapın.
Metin araması sıkça tuzaktır. Her tuş vuruşunda sorgu çalıştırırsanız, istek birikimi ve titreyen bir UI oluşturursunuz. Arama girişini debounce edin, kullanıcı durakladığında sorgu çalıştırın ve yeni bir istek başladığında eski istekleri iptal edin. Basit kural: kullanıcı hâlâ yazıyorsa sunucuya gitmeyin.
Filtreleme hızlı hissettirmek için aynı zamanda açık olmalı. Filtre çiplerini tablonun üstüne gösterin ki kullanıcılar hangi filtrelerin aktif olduğunu görebilsin ve tek tıklamayla kaldırsın. Çip etiketlerini ham alan adları yerine insan dostu tutun (ör. Owner: Sam yerine owner_id=42). "Sonuçlarım kayboldu" diyen birinin çoğu kez nedeni görünmez bir filtredir.
Büyük listeleri karmaşıklaştırmadan duyarlı tutan desenler:
Kaydedilmiş görünümler sessiz kahramandır. Kullanıcıya her seferinde mükemmel filtre kombinasyonunu öğretmek yerine, gerçek iş akışlarına uyan birkaç ön ayar verin. Bir operasyon ekibi bugün Başarısız ödemeler ile Yüksek değerli müşteriler arasında tek tıkta geçiş yapabilir. Bunlar bir tıkla, anında anlaşılır ve backend'de hızlı tutulması kolaydır.
Koder.ai gibi sohbet odaklı bir oluşturucuda dahili bir araç inşa ediyorsanız, filtreleri ek bir özellik değil ürün akışının bir parçası olarak ele alın. En yaygın sorulardan başlayın, sonra varsayılan görünümü ve kaydedilmiş görünümleri buna göre tasarlayın.
Bir liste ekranı nadiren detay sayfasıyla aynı verilere ihtiyaç duyar. API her şeyin her şeyini döndürürse iki kez ödersiniz: veritabanı daha fazla iş yapar ve tarayıcı kullanmayacağı kadar fazla veri alır ve render eder. Sorgu şekillendirme, listede şu anda neye ihtiyaç varsa sadece onu isteme alışkanlığıdır.
Öncelikle her satırı render etmek için gereken sütunları dönün. Çoğu panoda bu id, birkaç etiket, durum, sahip ve zaman damgalarıdır. Büyük metin, JSON blob'ları ve hesaplanan alanlar, kullanıcı satırı açana kadar bekleyebilir.
İlk boyama için ağır join'lerden kaçının. Join'ler indekslere çarptığında ve küçük sonuç döndürdüğünde uygundur, ama birden fazla tabloya join yapıp ardından join edilmiş verilere göre sıralama veya filtreleme yaparsanız pahalılaşır. Basit bir desen: listeyi tek bir tablodan hızlıca çekin, sonra görünür satırlar için ilgili detayları talep üzerine (veya batch olarak) yükleyin.
Sıralama seçeneklerini sınırlı tutun ve indeksli sütunlarla sıralayın. "Her şeye göre sırala" kulağa faydalı gelir ama genellikle büyük veri setlerinde yavaş sıralamalara zorlar. created_at, updated_at veya status gibi birkaç öngörülebilir seçenek tercih edin ve bunların indekslendiğinden emin olun.
Sunucu tarafı toplulaştırmalarda dikkatli olun. Büyük filtrelenmiş bir sette COUNT(*), geniş bir sütunda DISTINCT veya toplam sayfa hesaplamaları yanıt sürenizi domine edebilir.
Pratik yaklaşım:
COUNT ve DISTINCT gibi işlemleri isteğe bağlı tutun, önbellekleme veya yaklaşık gösterim kullanınKoder.ai ile dahili araçlar inşa ediyorsanız, planlama modunda hafif bir liste sorgusunu detay sorgusundan ayrı tanımlayın ki UI veri büyüdükçe hızlı kalsın.
100k satırlık bir listede hızlı kalmak istiyorsanız, veritabanının her istekte daha az iş yapması gerekir. Çoğu yavaş liste "çok fazla veri" değil; yanlış veri erişim desenidir.
Kullanıcıların gerçekte ne yaptığını yansıtan indekslerle başlayın. Listeniz genellikle status ile filtrelenip created_at ile sıralanıyorsa, bu iki alanı destekleyen bir indeks isteyin. Aksi halde veritabanı beklenenden çok daha fazla satır tarayıp sonra sıralamak zorunda kalabilir ve bu hızla pahalılaşır.
Genelde büyük kazanımlar sağlayan düzeltmeler:
tenant_id, status, created_at).OFFSET sayfaları yerine keyset (cursor) sayfalama tercih edin. OFFSET veritabanının birçok satırı atlamasına neden olur.Basit örnek: Müşteri adı, durum, tutar ve tarih gösteren bir Orders tablosu. Liste görünümü için tüm ilişkili tabloları join edip tam sipariş notlarını çekmeyin. Tabloya kullanılan sütunları döndürün, geri kalanı kullanıcı bir siparişi tıkladığında ayrı istekte alın.
Koder.ai gibi bir platformla inşa ediyorsanız, bu zihniyeti koruyun: üretilen API uç noktalarının cursor sayfalama ve seçici alan desteği olduğundan emin olun ki veritabanı işleri tablo büyüdükçe öngörülebilir kalsın.
Bir liste sayfası bugün yavaşsa, her şeyi yeniden yazmayla başlamayın. Normal kullanımın ne olduğunu kilitleyip ardından o yolu optimize edin.
Varsayılan görünümü tanımlayın. Varsayılan filtreleri, sıralamayı ve görünen sütunları seçin. Listeler her şeyi varsayılan olarak göstermeye çalıştığında yavaşlar.
Kullanımınıza uygun bir sayfalama stili seçin. Kullanıcılar çoğunlukla ilk birkaç sayfayı tarıyorsa klasik sayfalama yeterlidir. Eğer insanlar derinlere (sayfa 200+) atlıyorsa veya mesafe ne olursa olsun stabil performans gerekiyorsa keyset sayfalama kullanın (ör. created_at + id).
Tablo gövdesi için sanallaştırma ekleyin. Backend hızlı olsa bile, tarayıcı çok fazla satırı render edince takılabilir.
Arama ve filtreleri anında hissettirin. Yazmayı debounce edin ki her tuşa basmada istek atılmasın. Filtre durumunu URL veya tek bir paylaşılan durum deposunda tutun ki yenileme, geri butonu ve görünüm paylaşımı güvenilir çalışsın. Son başarılı sonucu önbelleğe alın ki tablo boş görünüp tekrar dolmasın.
Ölçün, sonra sorgu ve indeksleri iyileştirin. Sunucu süresini, veritabanı süresini, yük boyutunu ve render süresini loglayın. Sonra sorguyu daraltın: sadece gösterdiğiniz sütunları seçin, filtreleri erkenden uygulayın ve varsayılan filtre + sıralamayı destekleyen indeksler ekleyin.
Örnek: 100k ticket içeren bir destek panosu. Varsayılan olarak Açık, benim ekibime atanmış, en yeniye göre sıralı olsun; altı sütun gösterin ve sadece ticket id, subject, assignee, status ve zaman damgalarını çekin. Keyset sayfalama ve sanallaştırma ile hem veritabanı hem UI öngörülebilir kalır.
Koder.ai ile inşa ediyorsanız, bu plan Iterate-and-check iş akışına iyi uyar: görünümü ayarlayın, kaydırma ve aramayı test edin, sonra sorguyu iyileştirip sayfa aniden yavaşlamayana kadar ölçün.
Bir liste ekranını berbat hissettiren en hızlı yol 100k satırı normal bir sayfa verisi gibi işlemektir. Çoğu yavaş panoda birkaç tahmin edilebilir tuzak vardır.
Bunlardan biri her şeyi render edip CSS ile gizlemektir. Görünürde sadece 50 satır olsa bile tarayıcı 100k DOM düğümü oluşturmak, ölçmek ve kaydırmada yeniden boyamak için ödeme yapar. Uzun listeler gerekiyorsa sadece görüleni render edin (sanallaştırma) ve satır bileşenlerini basit tutun.
Arama, her tuşa basmada tam tablo taraması tetiklediğinde performansı sessizce mahvedebilir. Bu, filtrelerin indekslenmemiş olması, çok fazla sütunda aranması veya büyük metin alanlarında contains sorguları yaparken bir plan olmaması durumunda olur. İyi kural: kullanıcının ilk başvuracağı filtre veritabanında ucuz olmalı, sadece UI'da kullanışlı olmamalı.
Başka yaygın bir sorun da liste için özet gereken yerde tam kayıtları çekmektir. Bir liste satırı genellikle 5–12 alan gerektirir, tüm nesne değil, uzun açıklamalar değil ve ilişkili veri değil. Fazla veri çekmek veritabanı işini, ağ süresini ve frontend ayrıştırmayı arttırır.
Dışa aktarma ve toplamlar ana iş parçacığını dondurabilir veya ağır bir isteğin bitmesini bekletirse UI donabilir. UI etkileşimli kalmalı: dışa aktarmayı arka planda başlatın, ilerlemeyi gösterin ve toplamları her filtre değişikliğinde yeniden hesaplamaktan kaçının.
Son olarak, çok fazla sıralama seçeneği ters tepebilir. Kullanıcılar her sütuna göre sıralama yapabiliyorsa büyük sonuç kümeleri bellekte sıralanır veya veritabanını yavaş planlara zorlanır. Sıralamaları küçük bir indeksli sütun setiyle sınırlayın ve varsayılan sıralamanın gerçek bir indeksi takip etmesini sağlayın.
Hızlı kontrol:
Liste performansını tek seferlik bir düzeltme olarak değil bir ürün özelliği gibi ele alın. Bir liste ekranı gerçek insanlar gerçek verilerle kaydırırken, filtrelerken ve sıralarken hızlı hissettiğinde hızlıdır.
Bu kontrol listesiyle doğru şeyleri düzelttiğinizi doğrulayın:
Basit bir gerçek kontrol: listeyi açın, 10 saniye kaydırın, sonra yaygın bir filtre uygulayın (ör. Durum: Açık). Eğer UI donar, sorun genellikle render (çok fazla DOM satırı) veya her güncellemede gerçekleşen ağır istemci tarafı dönüşümdür (sıralama, gruplayıcı, formatlama).
Sırayla yapılacaklar:
Koder.ai ile (koder.ai) inşa ediyorsanız, Planning Mode'da başlayın: tam liste sütunlarını, filtre alanlarını ve API yanıt şeklini ilk başta tanımlayın. Sonra deneyler yapın ve bir değişiklik ekranı yavaşlatırsa geri alın.
Hedefi “her şeyi yükle” anlamından “ilk faydalı satırları hızlıca göster” olarak değiştirmekle başlayın. İlk satıra ulaşma süresini ve filtreleme, sıralama, kaydırma sırasında etkileşimin yumuşak kalmasını optimize edin; tüm veri seti aynı anda yüklenmeyebilir.
Bir yükleme veya filtre değişikliğinden sonra ilk satırın görünmesi için geçen süreyi, filtre/sıralamanın güncellenme süresini, yanıt yük boyutunu, yavaş veritabanı sorgularını (özellikle geniş SELECTler ve COUNT(*)) ve tarayıcı ana iş parçacığı sıçramalarını ölçün. Bu metrikler kullanıcıların algıladığı “gecikme”yle doğrudan ilişkilidir.
API'yi geçici olarak aynı filtre ve sıralamayla sadece 20 satır dönecek şekilde sınırlayın. Hızlanırsa sorun çoğunlukla sorgu maliyeti veya yük boyutudur; hâlâ yavaşsa darboğaz genellikle render, formatlama veya satır başına yapılan istemci tarafı işlemlerdir.
Binlerce satırı aynı anda DOM'a koymayın, satır bileşenlerini basit tutun ve sabit satır yüksekliğini tercih edin. Ayrıca ekran dışında kalan satırlar için pahalı formatlama işleri yapmayın; bir satır görünür olunca hesaplayın ve önbelleğe alın.
Virtualization, yalnızca görünen satırları (artı küçük bir tampon) monte ederek aynı DOM öğelerini yeniden kullanır. Çok kaydırma yapan veya ağır satırlara sahip listelerde uygundur ama en iyi sonucu sabit satır yüksekliği ve öngörülebilir tablo düzeniyle verir.
Çoğu yönetici ve dahili iş akışı için sayfalama (pagination) genelde en güvenli varsayımdır; kullanıcıyı yönlendirir ve sunucu yükünü sınırlar. Sonsuz kaydırma (infinite scroll) rahat gelebilir ama gezinmeyi ve bellek kullanımını zorlaştırabilir; arada bir "Daha fazla yükle" düğmesi iyi bir orta yol olabilir.
Offset sayfalama (page=10&size=50) daha basittir ama derin sayfalarda veritabanının çok fazla satır atlamasına neden olabilir. Keyset (cursor) sayfalama, genellikle created_at veya id gibi bir işaretçi kullanarak daha tutarlı performans sağlar, ancak belirli bir sayfaya atlamaya uygun değildir.
Her tuşa basmada istek yapmayın. Girdi alanını debounce edin, yeni istek başladığında devam eden eski istekleri iptal edin ve ilk sorgunun küçük ve faydalı olması için daraltılmış varsayılan filtreler (ör. Son 7 gün, Benim öğelerim) kullanın.
Liste sadece görüntülediği alanları döndürmeli: genellikle id, etiket, durum, sahip ve zaman damgaları gibi küçük bir alan seti. Büyük metin, JSON veya ilişkili veriler detay isteğine bırakılmalı, böylece ilk paint hafif ve öngörülebilir olur.
Varsayılan filtre ve sıralamayı gerçek kullanımınıza göre belirleyin, ardından bu modele uyan indeksler ekleyin (çoğu zaman bileşik indeksler). Kesin toplamları isteğe bağlı tutun; sayıları önbelleğe alın veya yaklaşık gösterin ki bunlar ana liste yanıtını yavaşlatmasın.