ID Üretimi ve Batch Insert — 200 Satır Kaç Gidiş Dönüş?
Önce şunu oku: Persistence Context — Hibernate'in Hafızası
30 saniyede özet
IDENTITY ile her yeni satırın numarası ancak veritabanına yazılınca belli olur, bu yüzden Hibernate satırları tek tek gönderir. Sequence ise numaraları 50'şerlik bloklarla önceden alır ve toplu yazmaya izin verir.
Paketlerini tek bir araçla göndermek istiyorsun, ama her paketin numarasını ancak merkeze ulaşınca alabiliyorsun. Araç bir türlü dolmuyor.
-
Bayt: Binlerce satırı içe aktarmak yavaştı. Toplu yazmayı açan ayarı ekledik!
-
Sen: Hızlandı mı?
-
Bayt: Süre hiç değişmedi! Ayar sanki hiç yokmuş gibi.
-
Bayt: Toplu gönderim için her paketin numarası baştan belli olmalı. Numarayı kim, ne zaman veriyor?
Binlerce satırlık içe aktarma yavaştı; ekip toplu yazmayı açan hibernate.jdbc.batch_size=50 ayarını ekledi. Süre hiç değişmedi ve sebep tek bir anotasyondu.
Id ne zaman belli olur?
Hibernate, persist edilen bir entity’yi persistence context’te id’siyle izler. Bu yüzden id’yi hemen bilmek zorundadır.
IDENTITYID'nin veritabanında INSERT sırasında üretildiği strateji (auto increment). Hibernate id'yi öğrenmek için INSERT'i hemen çalıştırır; bu yüzden batch yapamaz.Sözlükte gör →’de id’yi veritabanı INSERT sırasında üretir. Hibernate’in tek yolu INSERT’i persist anında çalıştırmaktır. Sequence’te ise id önceden alınır ve INSERT commit’e kadar bekleyebilir.
Kafam karıştı, daha basit anlat
IDENTITY’de numarayı kasa verir, bu yüzden her müşteri tek tek kasaya gitmek zorundadır. Sequence’te ise numaralar önceden bir deste hâlinde alınır.
@GeneratedValue(strategy = GenerationType.IDENTITY) kullanan bir entity'yi persist ettiğinde INSERT ne zaman çalışır?
@SequenceGenerator varsayılan allocationSize değeri 50. Bunun anlamı ne?
Batch neden işlemiyor?
JDBC batchingAynı SQL'i farklı parametrelerle birden çok kez tek gidiş dönüşte göndermek. Hibernate'te hibernate.jdbc.batch_size ile açılır; varsayılan olarak kapalıdır.Sözlükte gör →, aynı SQL’i birçok parametreyle tek gidiş dönüşte gönderir. Hibernate’te varsayılan olarak kapalıdır.
IDENTITY kullanan 200 entity, batch_size=50 açık. Kaç INSERT çağrısı gider? Cevabı göster
200. IDENTITY insert’leri persist anında tek tek çalışır; biriktirilecek bir batch yoktur. Hibernate ayarı hata vermeden yok sayar.
Adım adım oku
- IDENTITY'de id'yi veritabanı verir ve ancak satır yazılınca belli olur.
- Hibernate id'yi hemen bilmek zorunda olduğu için her entity'yi hemen ve ayrı ayrı yazar: toplu yazma devre dışı kalır.
- SEQUENCE ile veritabanı önceden bir numara bloğu verir; Hibernate numaraları kendi dağıtır.
- Bütün entity'ler numaralı olduğu için yazma işi biriktirilir ve tek bir toplu INSERT olarak gider.
Sequence ile batch mümkündür, ama bir tuzak daha var. Bir batch tek bir SQL şekli taşır: order, line, order, line sırası batch’i her seferinde kapatır. hibernate.order_inserts=true insert’leri tabloya göre sıralar.
Kafam karıştı, daha basit anlat
Batching, yüz mektubu tek zarfa koyup bir kez göndermektir. Ama IDENTITY her mektubu hemen yollamak zorunda olduğu için zarfta birikecek bir şey kalmaz.
hibernate.jdbc.batch_size=50 ayarladın, ama SQL log'unda hâlâ her satır için ayrı INSERT görüyorsun. Entity'ler IDENTITY kullanıyor. Neden?
Her ID stratejisini, batch insert ile ilişkisine göre ayır.
Kendin gör
200 satır kaç gidiş dönüş?
Tohum 518743Oynat ya da adımla.
Şu an ne oldu?
IDENTITY (auto increment)
Kod aynı: bir döngüde persist. Kaç SQL çağrısı gideceğini ID stratejisi ve iki ayar belirliyor.
Görevler0/3
batch_size açıkken yine de 200 ayrı INSERT gönderaçık
İpucu
ID stratejisine bak.
Pooled sequence ve batch açık, ama her batch tek satıraçık
İpucu
Insert sırası.
200 satırı 10'dan az gidiş dönüşle yazaçık
İpucu
Doğru ID stratejisi ve iki ayar.
Olay günlüğü (0)
Henüz olay yok. Oynat veya adımla.
- Varsayılanla oynat. IDENTITY, batch açık: yine 200 INSERT.
- “SEQUENCE, allocationSize 1” seç. INSERT’ler batch’lendi, ama 200 sequence çağrısı var.
- “allocationSize 50 (pooled)” seç. Toplam 8 gidiş dönüş.
- order_inserts’i kapat. Batch açık, ama her batch tek satır.
Pooled sequence ve batch_size=50 ayarlı. 10.000 siparişi içe aktaran iş yine de binlerce ayrı INSERT gönderiyor ve bellek sürekli büyüyor. Hatalı satırlar hangileri?
Tuzaklar
Sequence artışı ile allocationSize uyuşmazlığı. pooled optimizerSequence'ten tek çağrıda allocationSize kadar id ayıran Hibernate stratejisi. JPA'da varsayılan allocationSize 50'dir; sequence'in artışı da buna eşit olmalıdır.Sözlükte gör → sequence’in her çağrıda 50 arttığını varsayar. Sequence INCREMENT BY 1 ise düğümler çakışan id aralıkları alabilir.
Kendi atadığın id ve save(). Id dolu bir entity’yi Spring Data yeni saymaz ve merge çağırır; her INSERT’ten önce bir SELECT gider. Persistable ya da @Version kullan.
Tek persistence context’te binlerce entity. Batch gönderilse bile entity’ler bellekte birikir. Döngüde her batch’te flush() ve clear() çağır.
Id'yi uygulamada UUID olarak kendin atadığın bir entity'yi Spring Data'nın save() metoduyla kaydediyorsun. SQL log'unda her INSERT'ten önce bir SELECT görüyorsun. Neden?
Pooled sequence kullanan bir tabloda id'ler 1, 2, 3, 51, 52, 101 diye gidiyor. Ne düşünmelisin?
Aşağıdaki örnek bir bankanın gece işlediği POS takas dosyasından; her satır iki kayıtlı bir yevmiye fişine dönüşür. Toplu yazma uçtan uca: pooled sequence ile id, sequence’lerin doğru artışla oluşturulması, sıralı batch’ler, periyodik flush/clear ve id’yi uygulamada üreten bir entity için gereksiz SELECT’ten kaçış.
Derinleş · Gece POS takas dosyası: yevmiye kayıtları, az gidiş dönüş 5 dosya · ~148 satır · ilk okumada atlayabilirsin
Kendini sına
IDENTITY ile id, satır veritabanına yazılınca belli olur.
Batch insert Hibernate tarafında çalışıyor (log'da 50'lik batch'ler var), ama PostgreSQL log'unda hâlâ tek tek INSERT'ler görünüyor. Ne eksik olabilir?
Aklında kalacak üç şey
- 1 IDENTITY stratejisinde Hibernate INSERT'i hemen çalıştırır. batch_size ayarlı olsa bile bu satırlar toplu gönderilmez.
- 2 Pooled sequence tek seferde allocationSize kadar numara ayırır; veritabanındaki sequence'in artışı da bu değere eşit olmalıdır.
- 3 Toplu yazma için üç şey gerekir: önceden bilinebilen bir id, hibernate.jdbc.batch_size ve eklemeleri sıralayan order_inserts.
5 kart sonraki derste seni bekliyor