InnoDB satır sayısını neden saklamaz?


19

Herkes, InnoDB'yi motor olarak kullanan tablolarda SELECT COUNT(*) FROM mytable, özellikle tablo büyüdükçe ve bu sorgu yürütülürken sürekli satır ekleme / silme olduğunda, gibi sorguların çok hatalı ve çok yavaş olduğunu bilir .

Anladığım kadarıyla, InnoDB satır sayısını dahili bir değişkende saklamıyor, bu da bu sorunun nedeni.

Sorum şu: Bu neden böyle? Bu tür bilgileri depolamak çok zor olur mu? Birçok durumda bilmek önemli bir bilgidir. Böyle bir dahili sayımın uygulanıp uygulanmayacağını gördüğüm tek zorluk, işlemlerin gerçekleştiği zamandır: işlem taahhüt edilmezse, eklenen satırları sayar mısınız yoksa saymaz mısınız?

Not: DB'lerde uzman değilim, sadece basit bir hobi olarak MySQL'e sahip biriyim. Eğer aptalca bir şey sorduğumda, aşırı derecede eleştirel olmayın: D.


6
Yavaş, evet. Yanlış, hayır. Yavaş çünkü kesin sonuç veriyor. 200M satırlar tablonuz ve muhtemelen aynı tabloya ekleme / silme gibi birçok işlem, muhtemelen saniyede birçok satır olduğunda, başka bir soru "tam sayıya ihtiyacınız var mı?"
ypercubeᵀᴹ

@ypercube Ben phpmyadmin birkaç satır çok kapalı bazı satır sayısı değerleri gördüm biliyorum. Ayrıca, orada "doğru olmayabilir" gibi bir yorum var.
Radu Murzea

1
@RaduMurzea phpMyAdmin kullanıcıları, bildiğiniz hız nedenleriyle InnoDB tabloları için tablo sayılarını hesaplamak için alternatif bir yöntemdir. Bahsettiğiniz masumiyet burada devreye giriyor. Gerçek SELECT COUNT(*) FROM ...sorgular kesindir. İsterseniz, phpMyAdmin her zaman hız pahasına kesin satır sayılarını kullanacak şekilde yapılandırılabilir. Daha fazla bilgi: stackoverflow.com/questions/11926259/…
DOOManiac

Yanıtlar:


9

@RemusRusanu'ya katılıyorum (cevabı için +1)

SELECT COUNT(*) FROM mydb.mytableInnoDB bir işlem depolama motoru gibi davranır. MyISAM ile karşılaştırın.

MyISAM

Eğer mydb.mytablebir MyISAM tablodur, fırlatma SELECT COUNT(*) FROM mydb.mytable;çok geçmeden gibidir SELECT table_rows FROM information_schema.table WHERE table_schema = 'mydb' AND table_name = 'mytable';. Bu, MyISAM tablosunun başlığındaki satır sayısının hızlı bir şekilde aranmasını tetikler.

InnoDB'nin

Eğer mydb.mytablebir InnoDB tablosu ise, her şeyin yolunda gitmesini sağlarsınız. MVCC devam ediyor ve aşağıdakileri yönetiyor:

  • ib_logfile0 / ib_logfile1 (Günlükleri Yeniden Yap)
  • ibdata1
    • Günlükleri Geri Al
    • rollbacks
    • Veri Sözlüğü Değişiklikleri
  • Tampon Havuzu Yönetimi
  • İşlem İzolasyonu (4 tip)
    • Tekrarlanabilir Okumalar
    • Okundu Gönderildi
    • Kullanılmayan Oku
    • Serileştirilebilir

InnoDB'den bir tablo sayısı istemek, bu uğursuz şeylerde gezinmeyi gerektirir. Aslında, hiç kimse gerçekten SELECT COUNT(*) from mydb.mytabletekrarlanabilir okumaları sayar mı yoksa taahhüt edilmiş ve taahhüt edilmemiş okumaları da içerir.

İnnodb_stats_on_metadata'yı etkinleştirerek işleri biraz dengelemeyi deneyebilirsiniz .

İnnodb_stats_on_meta_data üzerindeki MySQL Belgelerine göre

Bu değişken etkinleştirildiğinde (değişken oluşturulmadan önceki varsayılan değerdir), InnoDB, SHOW TABLE STATUS veya SHOW INDEX gibi meta veri deyimleri sırasında veya BİLGİ_SCHEMA tabloları TABLOLAR veya İSTATİSTİK'ye erişirken istatistikleri günceller. (Bu güncellemeler ANALYZE TABLE için olanlara benzer.) Devre dışı bırakıldığında, InnoDB bu işlemler sırasında istatistikleri güncellemez. Bu değişkeni devre dışı bırakmak, çok sayıda tablo veya dizin içeren şemaların erişim hızını artırabilir. Ayrıca, InnoDB tablolarını içeren sorgular için yürütme planlarının kararlılığını artırabilir.

Devre dışı bırakılması, EXPLAIN planlarının oluşturulması açısından size daha istikrarlı bir sayı verebilir veya vermeyebilir. Performansını SELECT COUNT(*) from mydb.mytableiyi bir şekilde, kötü bir şekilde etkileyebilir veya hiç etkilemeyebilir . Bir deneyin ve görün !!!


16

Başlangıç ​​için, bir değişkende saklanacak 'geçerli sayım' diye bir şey yoktur. Gibi bir sorgu SELECT COUNT(*) FROM ...geçerli yalıtım düzeyine ve eşzamanlı bekleyen tüm işlemlere tabidir. Yalıtım düzeyine bağlı olarak, sorgu bekleyen işlemlerin eklenmesiyle eklenen veya silinen satırları görebilir veya göremez. Yanıtlamanın tek yolu, geçerli işlem tarafından görülebilen satırları saymaktır.

Sayım sırasında başlayan veya biten eşzamanlı işlemlerin daha da dikenli konusuna bile dokunmadığımı unutmayın . Geri dönüşlerden bahsetmiyorum bile ...


1
Tamam, bu anlam seviyesine bağlı, bu mantıklı. Ancak yine de uygulanabilir.
Radu Murzea

@SoboLAN Çoğu yukarıda listelenen olmamalı ve olmamalıdır birçok nedeni vardır. İşlem başlangıcında tablo başına sayımların listesini tutarak (Oracle'ın SCN'si MySQL'de ne olursa olsun) uygular mısınız? Bu tür sayıları yönetmek büyük bir ek yük olacaktır - her biri aynı tabloda büyük miktarda INSERT / DELETE yapan 100'ler veya 1000'ler eşzamanlı oturum içeren bir veritabanı düşünün. Bakımı imkansız.
Philᵀᴹ

Bunu uygulamak oldukça zordur. Sayının DB'de kalıcı olması gerektiğini, yani meta verilerde bir yer anlamına geldiğini ve bu sayının bir satır ekleyen veya silen her işlem tarafından sürdürülmesi gerektiğini düşünün . Bu meta verileri nasıl kilitlersiniz ? Ve geri dönüşleri nasıl ele alırsınız? Önemsiz olmaktan uzaktır. Ve sonuç, çok dar bir sorgu alt kümesi için kullanılabilir.
Remus Rusanu

3
@JackDouglas İlginç. Geçmişteki COUNT(*)sorgularda gördüğüm kadarıyla , gerçekte nadiren ihtiyaç duyulur ve genellikle geliştirici deneyimsizliğinin (bunları seçmeden önce satırları sayın!) Veya kötü uygulama tasarımının sonucudur.
Philᵀᴹ

1
@SoboLAN - hayır, olmaz. Önceden tanımlanmış zaman aralıklarında bir tür istatistik tablosunu güncelleyen bir hizmete sahip olmak çok daha iyidir. Büyük bir veritabanına ve tabloların çoğunu sorgulayan birkaç yöneticiye sahip olduğunuzu düşünün , tabloya SELECT COUNT(*)optimize edilmemiş bir WHEREşekilde ekleyin ve birkaç kullanıcıyı, şüphesiz yararlı birkaç istatistik sayacı için dizlerine getiren birkaç kullanıcınız olacak.
NB

0

Teorik olarak, InnoDB ile belirli bir tablo için satır sayısını doğru bir şekilde tutmak mümkün olsa da, performansı olumsuz etkileyecek çok fazla kilitleme pahasına olacaktır. Ayrıca izolasyon seviyesine bağlı olarak da farklılık gösterir.

MyISAM zaten masa seviyesi kilitleme yapıyor, bu yüzden orada ekstra bir maliyet yok.

Ben biraz COUNT (*) kullanmak rağmen nadiren bir tablo için bir satır sayısı gerektirir. Genelde bir WHERE yan tümcesi ekliyorum. Küçük bir sonuç kümesinde verimli bir indeks kullanarak, bunların yeterince hızlı olduğunu fark ettim.

Sayımların yanlış olduğunu kabul etmiyorum. Sayımlar, verilerin anlık bir görüntüsünü temsil eder ve her zaman tam olarak buldum.

Kısacası, MySQL bunu InnoDB için uygulamayı size bırakır. Her sorgudan sonra bir sayı kaydedebilir ve artırabilir / azaltabilirsiniz. Yine de, daha kolay çözüm muhtemelen MyISAM'a geçmektir.


2
Bu var olmayan bir işlem sisteminde satırların doğru bir sayım tutulması mümkün. Çünkü aktif işlemler kadar farklı (ve doğru) satır sayısı vardır.
a_horse_with_no_name

5
Burada '-1' olsa da, daha kolay çözüm muhtemelen MyISAM'a geçmek. Asla sadece satır sayısını almak için MyISAM'a geçmenizi tavsiye etmem.
Derek Downey

@a_horse_with_no_name, her işlem için "doğru" bir satır sayısı olacağını kabul edersiniz. Benim için mümkün görünüyor.
Marcus Adams

1
@Dest, asla "sadece satır sayısını almak için" demedim.
Marcus Adams

@a_horse_with_no_name, Bu doğru görünmüyor. Şüphesiz biz sadece işlemleri alır satır sayısını sayan kararlı hakkı?
Pacerier
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.