Hangisi daha hızlı: birden çok tek INSERT mi yoksa bir çok satırlı INSERT mi?


184

MySQL veri ekler kodumu bir bölümünü optimize etmeye çalışıyorum. INSERT'leri büyük bir çok satırlı INSERT yapmak için zincirlemeli miyim yoksa birden fazla ayrı INSERT daha hızlı mı olmalı?

Yanıtlar:


287

https://dev.mysql.com/doc/refman/8.0/en/insert-optimization.html

Bir satır eklemek için gereken süre, sayıların yaklaşık oranları gösterdiği aşağıdaki faktörlerle belirlenir:

  • Bağlanıyor: (3)
  • Sorguyu sunucuya gönderme: (2)
  • Sorgu ayrıştırma: (2)
  • Satır ekleme: (1 × satır boyutu)
  • Dizin ekleme: (1 × dizin sayısı)
  • Kapanış: (1)

Bundan, açık bir şekilde, büyük bir ifade göndermenin, ekleme ifadesi başına 7 ek yükü kurtaracağı açıktır;

Aynı istemciden aynı anda birden çok satır ekliyorsanız, aynı anda birden çok satır eklemek için birden çok VALUES listeli INSERT ifadeleri kullanın. Bu, tek satırlık ayrı INSERT ifadeleri kullanmaktan çok daha hızlıdır (bazı durumlarda birçok kez daha hızlıdır).


27
Aynı veritabanı işlemi içinde birden fazla INSERT varsa bu cevap nasıl uygulanır?
çimdik

2
Tek insert deyimini kullanarak bir seferde kaç satır ekleyebilirim. bir seferde 10000 satır eklememe izin veriyor mu?
Naresh Ramoliya

10
@Pinch ~ 1.5k upserts (insert / update) yaparken bir işlem kullanılması, işlemin ~ 1.5 saniyeden ~ 0.2 saniyeye düştüğü süreyi azalttı. Başka bir deyişle, tek sıralı kesici uçlara kıyasla% 86 daha hızlı yaptı. Lanet olsun.
fgblomqvist

1
Not:
MSSQL'de

Tekrarlanan birden fazla tekli insert eklemek için Hazırlanmış Deyimi kullanmaya ne dersiniz?
priyabagus

151

Ben o istendi neredeyse iki buçuk yıl sonra bu soruya cevap biliyorum, ama sadece şu anda gerçekten de ekin başına birden fazla DEĞER blokları yapıyor gösterileri olduğunu ben üzerinde çalıştığım bir projeden bazı zor verileri sağlamak istedik KADAR sıralı tek VALUE bloğundan daha hızlı INSERT ifadeleri.

C # 'da bu kıyaslama için yazdığım kod, bir MSSQL veri kaynağından (~ 19.000 satır, tümü herhangi bir yazma başlamadan önce okunur) belleğe veri okumak için ODBC kullanır ve MySql .NET bağlayıcı (Mysql.Data. *) Şeyler Verileri bellekten MySQL sunucusundaki bir tabloya hazırlanmış ifadeler aracılığıyla yerleştirin. Hazırlanan INSERT başına VALUE blok sayısını dinamik olarak ayarlamama izin verecek şekilde yazılmıştır (yani, bir çalıştırmadan önce n değerini ayarlayabileceğim bir seferde n satır ekle.) Ayrıca testi de çalıştırdım. her biri için birden çok kez

Tekli VALUE bloğu yapmak (örneğin, bir seferde 1 satır) çalıştırmak 5,7 - 5,9 saniye sürdü. Diğer değerler aşağıdaki gibidir:

Bir seferde 2 satır: 3,5 - 3,5 saniye
Bir seferde 5 satır: 2,2 - 2,2 saniye Her
seferinde 10 satır: 1,7 - 1,7 saniye Her
seferinde 50 satır: 1,17 - 1,18 saniye Her
seferinde 100 satır: 1,1 - 1,4 saniye
Bir seferde 500 satır: 1.1 - 1.2 saniye
Bir seferde 1000 satır: 1.17 - 1.17 saniye

Yani evet, sadece 2 veya 3 yazıyı bir araya getirmek bile, n = 5 ve n = 10 arasında bir yere ulaşana kadar, hızın çarpıcı bir şekilde iyileşmesini sağlar (n, bir faktör tarafından kesilir), ve n = 10 ila n = 50 aralığında bir yerde gelişme göz ardı edilebilir hale gelir.

İnsanların (a) çok hazırlılık fikrinin kullanılıp kullanılmayacağına ve (b) ifade başına kaç tane VALUE bloğu oluşturulacağına karar vermesine yardımcı olacağını umuyoruz (sorguyu maksimum sorgu boyutunu geçecek kadar büyük verilerle çalışmak istediğinizi varsayarsak) sunucuda max_allowed_packet değerine bağlı olarak muhtemelen daha büyük veya daha küçük birçok yerde varsayılan olarak 16MB olduğuna inanıyorum MySQL için.)


1
Açıklama isteği: süreniz "satır başına saniye" veya "toplam saniye" dir.
EngrStudent

3
Toplam saniye - satır başına saniye sayısı ~ 19.000 satıra bölünür. Bu küçük bir sayı olmasına rağmen, kolayca karşılaştırılabilir bir sayı arıyorsanız, belki de satır / saniye daha iyi bir metriktir.
Jon Kloske

Bu arada, bu ilgili
cevabımda

18

İşlemci bir motor kullanıp kullanmadığınız ve otomatik devreye girip girmediğiniz önemli bir faktördür.

Otomatik taahhüt varsayılan olarak açıktır ve muhtemelen açık bırakmak istersiniz; bu nedenle, yaptığınız her ekleme kendi işlemini yapar. Bu, her satır için bir ekleme yaparsanız, her satır için bir işlem yapacağınız anlamına gelir.

Tek bir iş parçacığı varsayıldığında, sunucunun HER SATIR için diske bazı verileri senkronize etmesi gerektiği anlamına gelir. Verilerin kalıcı bir depolama konumuna ulaşmasını beklemesi gerekir (umarım RAID denetleyicinizdeki pil destekli koç). Bu doğal olarak oldukça yavaştır ve muhtemelen bu durumlarda sınırlayıcı faktör olacaktır.

Tabii ki işlemsel bir motor (genellikle innodb) kullandığınızı ve dayanıklılığı azaltmak için ayarları değiştirmediğinizi varsayıyorum.

Ayrıca bu ekleri yapmak için tek bir iş parçacığı kullandığınızı varsayıyorum. MySQL'in bazı sürümlerinin innodb'de çalışma grubu taahhüdü bulunduğundan, birden çok iş parçacığı çamurunu biraz karıştırır - bu, kendi taahhütlerini yapan birden çok iş parçacığının işlem günlüğüne tek bir yazma paylaşabileceği anlamına gelir, çünkü bu, kalıcı depolama için daha az eşitleme anlamına gelir .

Öte yandan, çok satırlı uçları GERÇEKTEN KULLANMAK İSTEDİĞİNİZ.

Karşı üretken hale gelme sınırı vardır, ancak çoğu durumda en az 10.000 satırdır. Dolayısıyla, bunları 1000 satıra kadar topluyorsanız, muhtemelen güvendesiniz.

MyISAM kullanıyorsanız, başka bir şey daha var, ama sizi bunlarla sıkmayacağım. Barış.


1
Bir noktadan sonra karşı üretken olmasının bir nedeni var mı? Daha önce de olduğunu gördüm ama neden olduğundan emin değildim.
Dhruv Gairola

1
Zaman MySQL ekler harmanlanmasından içinde hiç bir anlamı olup olmadığını biliyor musunuz işlemlerini kullanmaya . Sadece temel kitaplığım (Java JDBC - mysql-connector-java-5.1.30) bunu söyleyene kadar işlemiyorsa, çok değerli SQL komutunu üretme zorluğunu kendim kurtarabilir miyim diye merak ediyorum.
RTF

@RTF Durumunuzda bu davranışı son derece uygulamaya özgü davranış olarak belirlemek için küçük bir test yapmanız gerektiğini düşünüyorum, ancak çoğu durumda evet işlemleri benzer performans kazanımları sağlamalıdır.
Jasmine Hegman

9

Tel boyunca mümkün olduğunca çok sayıda kesici uç gönderin. Gerçek yerleştirme hızı aynı olmalıdır, ancak ağ ek yükünün azalmasından kaynaklanan performans kazanımlarını göreceksiniz.


7

Genel olarak veritabanına yapılan çağrı sayısı ne kadar az olursa o kadar iyidir (yani daha hızlı, daha verimli), bu nedenle ekleri veritabanı erişimini en aza indirecek şekilde kodlamaya çalışın. Bir bağlantı havuzu kullanmadığınız sürece, her veritabanı erişiminin bir bağlantı oluşturması, sql yürütmesi ve ardından bağlantıyı yırtılması gerekir. Biraz havai!


kalıcı bağlantı kullanılırsa ne olur?
dusoft

6
Hala ek yük var. Binlerce insert yapıyorsanız, tek başına geçiş süresi (her ayrı insert için ve her bir insert için) hızlı bir şekilde algılanacaktır.
RC.

4

Şunları yapmak isteyebilirsiniz:

  • Otomatik taahhüdün kapalı olduğundan emin olun
  • Açık Bağlantı
  • Tek bir işlemde birden çok ek grubu gönderin (yaklaşık 4000-10000 satır boyutu?
  • Yakın bağlantı

Sunucu terazi (onun kesin olan ok ne kadar iyi bağlı olarak PostgreSQl, Oracleve MSSQL), çoklu iş parçacığı ve çoklu bağlantı ile yukarıdaki şeyi yap.


3

Genel olarak, bağlantı ek yükü nedeniyle birden fazla kesici uç daha yavaş olacaktır. Bir kerede birden fazla kesici uç kullanılması, kesici uç başına ek masrafı azaltır.

Hangi dili kullandığınıza bağlı olarak, muhtemelen db'ye gitmeden önce programlama / komut dosyası dilinizde bir toplu iş oluşturabilir ve her eki toplu işleme ekleyebilirsiniz. Daha sonra, bir bağlantı işlemini kullanarak büyük bir toplu iş yürütebilirsiniz. İşte Java'da bir örnek.


3

MYSQL 5.5 Bir sql insert deyimi ~ 300 ila ~ 450 ms sürdü. aşağıdaki istatistikler satır içi birden çok ekleme ifadesi içindir.

(25492 row(s) affected)
Execution Time : 00:00:03:343
Transfer Time  : 00:00:00:000
Total Time     : 00:00:03:343

Satır içi gitmek için bir yol olduğunu söyleyebilirim :)


0

Ekler söz konusu olduğunda Mysql ve MariaDB'nin ne kadar kötü optimize edildiği çok saçma. MySQL 5.7 ve mariadb 10.3'ü test ettim, bunlar üzerinde gerçek bir fark yok.

Bunu NVME diskleri, 70.000 IOPS, 1.1 GB / sn seq verimi olan bir sunucuda test ettim ve bu tam çift yönlü (okuma ve yazma).
Sunucu aynı zamanda yüksek performanslı bir sunucudur.
20 GB koç verdi.
Veritabanı tamamen boş.

Çok satırlı ekler alırken aldığım hız saniyede 5000 eklendi (1MB ila 10MB'lık veri parçalarıyla denedim)

Şimdi ipucu:
Başka bir iş parçacığı ekleyip aynı tablolara eklersem aniden 2x5000 / sn. Bir iplik daha ve toplam 15000 / sn var

Bunu düşünün: ONE iş parçacığı ekleri yaparken, diske sırayla yazabileceğiniz anlamına gelir (dizinler hariç). İş parçacıklarını kullanırken, olası performansı düşürürsünüz, çünkü artık çok daha rastgele erişim yapması gerekiyor. Ancak gerçeklik kontrolü, mysql'in o kadar kötü bir şekilde optimize edildiğini gösteriyor ki, iş parçacıkları çok yardımcı oluyor.

Böyle bir sunucu ile mümkün olan gerçek performans muhtemelen saniyede milyonlarca, CPU boşta, disk boşta.
Nedeni, mysql gibi içsel gecikmeler olduğu için oldukça açıktır.


@Craftables harici gelişime ihtiyacınız var, mysql içinde yapılamaz. İş parçacıkları, sunucuya birden çok bağlantı kullandığınız, sorguyu birden çok parçaya böldüğünüz anlamına gelir (örneğin, birincil anahtarla eşit parçalara bölerek). Çok büyük tablolarda bu yöntemi kullanarak performansın 10.000 katına ulaşmayı başardım. Birden fazla iş parçacığı kullanırsanız ve MySQL'iniz son derece optimize edilmişse, 40.000 saniye boyunca çalışacak sorgular 2-3 dakika içinde bitebilir.
John

@John İlginç ve bazı gerçek güzel uygulamalar olabilir ... ama ... Sorguyu birden fazla parçaya bölerseniz işlemleri nasıl ele alırsınız? Ve ayrıca aşağıdaki senaryoyu göz önünde bulundurun: Tablo x, aynı tablo 'id' ile ilişkili bir 'parent_id' sütununa sahiptir. Verilerinizin içinde bir yerde x ( id, parent_id) DEĞERLERİNE (1, NULL) GİRİN . Sonraki değer kümelerinden biri o satıra bağlanır. Parçalara ayrılırsanız ve bu set başka bir parçaya gelirse, ilk işlemden önce işlenebilir ve tüm işlem başarısız olur. Bununla nasıl başa çıkılacağı hakkında bir fikrin var mı?
zozo

@zozo, bu toplu ekler ve toplu sorgular için kullanışlıdır. Çok sayıda veri arabelleği içerdiğinden işlemler yine de performansı bozar. Ancak işlemleri çok iş parçacıklı eklerde veya sorgularda da kullanabilirsiniz.
John

-2

birden fazla kesici uç daha hızlıdır, ancak gerekir. başka bir thrik devre dışı bırakıyor kontrolleri geçici yapmak uçlar çok daha hızlı yapmak. Masanızın olması ya da olmaması önemli değil. Örneğin, yabancı anahtarları devre dışı bırakmayı test edin ve hızın tadını çıkarın:

SET FOREIGN_KEY_CHECKS=0;

ekler tarafından ekledikten sonra tekrar açmalısınız:

SET FOREIGN_KEY_CHECKS=1;

bu, büyük veri eklemenin yaygın yoludur. veri bütünlüğü bozulabilir, böylece yabancı anahtar kontrollerini devre dışı bırakmadan önce bununla ilgilenmelisiniz.


1
Ppl'in bunu iki nedenden ötürü neden iptal ettiği hakkında hiçbir fikrim yok: 1. Bunun soru ile ilgisi yok 2. Bu gerçekten kötü bir fikirdir (birkaç istisna dışında - damping veya yapısal sıcaklık değişiklikleri gibi - ancak genel olarak kötü). Kontroller bir nedenden dolayı var: Veri tutarlılığını sağlamak için oradalar. İşleri yavaşlatırlar, çünkü yapmamanız gereken verileri eklememenizi veya başka bir şekilde değiştirmemenizi sağlarlar. Sorguları doğru şekilde optimize etmeye çalışın; İş açısından kritik ortamlarda bu, uygulamanın ne kadar dikkatli olduğuna bakılmaksızın bir noktada başarısız olacağından uygulamanın ölümü anlamına gelir.
zozo

1
belki de bu seçenek büyük tabloları içe aktarmada son derece etkilidir ve çok pratiktir ve bazı insanlara veri eklemeyi nasıl daha hızlı hale getirebilecekleri hakkında bir fikir verebilir.
MSS
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.