MyISAM ve InnoDB'ye karşı [kapalı]


857

Ben ( 70% ekler ve% 30 okuma ) veritabanı yazma bir sürü içeren bir proje üzerinde çalışıyorum . Bu oran aynı zamanda bir okuma ve bir yazma olduğunu düşündüğüm güncellemeleri de içerir. Okumalar kirli olabilir (örneğin, okuma sırasında% 100 doğru bilgiye ihtiyacım yoktur).
Söz konusu görev, saatte 1 milyondan fazla veritabanı işlemi yapacak.

Web'de MyISAM ve InnoDB arasındaki farklar hakkında bir sürü şey okudum ve MyISAM, bu görev için kullanacağım belirli veritabanı / tablolar için bana bariz bir seçim gibi görünüyor. Okuduğum şeyden, satır düzeyinde kilitleme desteklendiğinden işlemlere ihtiyaç duyulursa InnoDB iyidir.

Bu tip yük (veya üstü) ile ilgili herhangi bir tecrübesi olan var mı? MyISAM gidilecek yol mu?


13
MySQL Performans blog şey bu tür için büyük bir kaynaktır.
ceejayoz

3
Bu, sisteminizin OLTP veya daha fazla veri ambarı odaklı (yazıların çoğunun toplu yükleme olduğu) olup olmamasına bağlı olacaktır.
nos

35
MyISAM satır kilitleme, işlemleri desteklemiyor, yabancı anahtarları bile desteklemiyor ... cehennem, çünkü ACID sağlayamıyor , hatta uygun bir veritabanı olarak kabul edilemiyor! Bu nedenle InnoDB, MySQL 5.5'ten beri varsayılan motor olmuştur ... ancak, ne olursa olsun, MyISAM, PhpMyAdmin'de oluşturulan tablolar için varsayılan motor olmaya devam etmektedir, bu nedenle MyISAM'de çalıştırıldığından beri birçok amatör veritabanı.
BlueRaja - Danny Pflughoeft


Yanıtlar:


523

Bu soruyu kısaca bir tabloda tartıştım , böylece InnoDB veya MyISAM ile gidip gelmeyeceğinize karar verebilirsiniz .

İşte hangi durumda hangi db depolama motorunu kullanmanız gerektiğini gösteren küçük bir genel bakış:

                                                 MyISAM InnoDB
-------------------------------------------------- --------------
Gerekli tam metin araması Evet 5.6.4
-------------------------------------------------- --------------
İşlem gerektir Evet
-------------------------------------------------- --------------
Sık seçilen sorgular Evet      
-------------------------------------------------- --------------
Sık sık ekleme, güncelleme, silme Evet
-------------------------------------------------- --------------
Sıra kilitleme (tek masada çoklu işleme) Evet
-------------------------------------------------- --------------
İlişkisel taban tasarımı Evet

özet

  • Hemen hemen her koşulda, InnoDB en iyi yol
  • Ancak, sık okuma, neredeyse hiç yazma, MyISAM kullanın
  • MySQL <= 5.5 içinde tam metin araması, MyISAM kullanın

11
InnoDB, MySQL 5.6'da tam metin dizinlerine sahiptir, ancak şu ana kadar üretim kullanımına gerçekten hazır değildir.
Bill Karwin

3
Tanımayacaklardır 12.9. Tam Metin Arama İşlevleri , “Tam metin dizinleri yalnızca InnoDB veya MyISAM tablolarıyla kullanılabilir”. MySQL> = 5.6 için uygun görünüyor, ancak MySQL 5.5 için aynı sayfa hala “Tam metin dizinleri yalnızca MyISAM tablolarıyla kullanılabilir” diyor. Yukarıdaki tablo MySQL sürümlerinden nasıl farklı olduğunu söyleyecek şekilde güncellenebilir. Ne yazık ki, şimdiye kadar, MySQL 5.5 standart gibi görünüyor.
Hibou57

2
Ne anlama geliyor InnoDB - full-text: 5.6.4? Evet ya da değil mi?

2
MyISAM ayrıca satır sayısını dahili olarak depolar. Bu nedenle, Count () işlevi MyISAM'de neredeyse ücretsizdir, oysa InnoDB'de fark edilir bir zaman alır.
Hedeshy

3
iyi tablo, ancak kalite ve istikrar için bir satır ekleyerek, MyIsam = hayır, innoDB = evet daha da iyi hale getirir
pilavdzice

268

Ben bir veritabanı uzmanı değilim ve deneyimden konuşmuyorum. Ancak:

MyISAM tabloları tablo düzeyinde kilitleme kullanır . Trafik tahminlerinize dayanarak, saniyede 200'e yakın yazma işlemine sahipsiniz. MyISAM ile bunlardan sadece biri her zaman devam ediyor olabilir . Taşmayı önlemek için donanımınızın bu işleme ayak uydurabildiğinden emin olmalısınız, yani tek bir sorgu en fazla 5 ms sürebilir.

Bu bana satır düzeyinde kilitlemeyi, yani InnoDB'yi destekleyen bir depolama motoruna ihtiyacınız olduğunu gösteriyor.

Öte yandan, her bir depolama motoruyla yükü simüle etmek için birkaç basit komut dosyası yazmak ve ardından sonuçları karşılaştırmak oldukça önemsiz olmalıdır.


12
200'e yakın mı? Ortalama işlemi 2.5 sorgu yaparsa, bu [(2.5 * 1M) / 3600s =] 700'e daha yakındır.
Ozzy

12
Ben de aynı fikirdeyim a single query can take no more than 5msçünkü 2 olası varsayım yapmadınız; A: tüm sorguların aynı tabloya ihtiyacı vardı & B: sadece 1 bağlantı mevcuttu! Yüksek RAM'li bir Linux ve MySQL 5.5 kurulumunun 10.000 eşzamanlı bağlantıyı destekleyebileceğini size bildirmeliyim (Bkz: dev.mysql.com/doc/refman//5.5/en/too-many-connections.html )
Ozzy

152
Bir tablo tablo kilitlendiğinde, aynı anda yalnızca bir sorgu çalıştırılabilir. Sunucunun 10000 eşzamanlı bağlantıyı desteklemesi önemli değildir, tablo kilitliyken her biri yedeklenir.
Ryaner

2
Ayrıca InnoDB desteklemediği halde MyISAM'ın uzamsal dizini desteklediğini bilmek de yararlı olabilir. Ve MyISAM, bir tane oluşturmayı engellemese de yabancı anahtarlar kullanmıyor gibi görünüyor.
Kriver

4
@kriver: MyISAM tablolarında yabancı anahtarınız olamaz. FK tanımlarını CREATE TABLE ifadelerine dahil edebilirsiniz, ancak bunlar (tanımlar) basitçe yok sayılır.
ypercubeᵀᴹ

191

İnsanlar genellikle performans, okumalar, yazmalar, yabancı anahtarlar, vb. Hakkında konuşurlar .

Bunu dene:

  1. MyISAM tablonuzda 5 saniye süren bir GÜNCELLEME yayınlayın.
  2. GÜNCELLEŞTİRME işlemi devam ederken, 2.5 saniye içinde, kesmek için Ctrl-C tuşlarına basın.
  3. Tablodaki etkileri gözlemleyin. Kaç satır güncellendi? Kaç tanesi güncellenmedi? Tablo okunabilir mi veya Ctrl-C'ye bastığınızda bozuk mu?
  4. UPDATE ile aynı denemeyi bir InnoDB tablosunda deneyin ve devam eden sorguyu yarıda kesin.
  5. InnoDB tablosuna bakın. Sıfır satır güncellendi. InnoDB, atomik güncellemeleriniz olduğundan emin olmuştur ve tam güncelleme yapılamazsa, tüm değişikliği geri alır. Ayrıca, tablo bozuk değil. Bu, killall -9 mysqldbir kilitlenme simülasyonu yapmak için kullansanız bile çalışır .

Performans elbette arzu edilir, ancak veri kaybı olmamalıdır.


4
Kayıt için, bir ACID veritabanının diğer özellikleri - Tutarlılık, Yalıtım ve Dayanıklılık - MyISAM tarafından da desteklenmez.
Bill Karwin

Ctrl-C tabloyu bozmamalıdır - KONTROL TABLOSU'ndaki başarı başarılı olur ve tüm sorgular hatasız olarak devam eder. MyISAM, tüm kayıtları güncellemeden güncellemeyi iptal eder, ancak tablo dahili yapısal bütünlüğü korur. MySQL'in SIGTERM ile öldürülmesi aynı etkiye sahip olacaktır. Bununla birlikte, SIGKILL (kill -9) veya bazı çökme sinyali verirseniz (veya bir hataya çarptığında kendi başına kazanır) veya işletim sistemi çökerse / güç kaybedilirse, farklı bir hikaye - görebilirsiniz MyISAM düzeyinde yolsuzluk.
Sasha Pachev

1
InnoDB kendisini kraliyet olarak da bozabilir, genellikle MyISAM'dan daha kraliyet olarak. ASİT'in ironisi, ya hep ya hiç fikrimizdir. Bu nedenle InnoDB her şeyi veremediğinde, hiçbir şey vermez - iç iddia ve hiçbir yapıda çalışmayı reddeder, çünkü bazı yapılardaki bir bayt yanlıştır - zamanın% 90'ı göz ardı edilebilirdi ve en fazla sadece bir tabloyu etkilerdi. Son Percona sunucuları bununla başa çıkma seçeneğine sahiptir - innodb_pass_corrupt_table.
Sasha Pachev

1
Son 3 gün içinde bu tür bilgileri araştırıyordum, şimdi anladım. InnoDB en iyisidir. TeşekkürlerBill Karwin
user3833682

3
@ flow2k, Bugünlerde neredeyse hiç yok. Son işimde MyISAM'ı bir sunucudaki bir tablo için kullandık ve bunun tek nedeni MyISAM'ın bu tabloyu InnoDB'den daha az alanda depolayabilmesiydi. Disk alanı üzerinde kısıtlandık, bu yüzden veritabanını başka bir sunucuya taşıyana kadar MyISAM kullanmak zorunda kaldık. Yeni işimde zaten her tablonun InnoDB olması gerektiğine dair bir politika var.
Bill Karwin

138

MySQL kullanarak yüksek hacimli bir sistem üzerinde çalıştım ve hem MyISAM hem de InnoDB'yi denedim.

MyISAM'deki tablo düzeyinde kilitlemenin, iş yükünüz için sizinkine benzer ciddi performans sorunlarına neden olduğunu buldum. Ne yazık ki, InnoDB altındaki performansın da umduğumdan daha kötü olduğunu buldum.

Sonunda ekler bir "sıcak" tabloya gitti ve seçimler asla sıcak tablo sorguladı veri parçalayarak çekişme sorunu çözüldü.

Bu aynı zamanda silme işlemlerine (veriler zamana duyarlıydı ve yalnızca X gün değerinde kaldık), seçili sorgular tarafından tekrar dokunulmayan "eski" tablolarda gerçekleşmesine izin verdi. InnoDB, toplu silme işlemlerinde düşük performansa sahip gibi görünüyor, bu nedenle verileri temizlemeyi planlıyorsanız, verileri eski veriler üzerinde silinmek yerine basitçe bırakılabilecek eski bir tabloda olacak şekilde yapılandırmak isteyebilirsiniz.

Tabii ki başvurunuzun ne olduğu hakkında hiçbir fikrim yok ama umarım bu size MyISAM ve InnoDB ile ilgili bazı sorunlar hakkında fikir verir.


3
'Sonunda ekler bir 'sıcak' tabloya gitti ve seçer sıcak tablo sorgulanan asla öyle ki veri parçalanması ile çekişme sorunu çözüldü ". - Bir şey aslında o değil arabellek havuzu ? İçindir
BlueRaja - Dany Pflughoeft

15
Danny - Hayır, pek değil. Sunucu ayarlarının yapılması önemlidir, ancak hiçbir şekilde şemanızın düşünceli yapılandırmasının yerini tutamaz. Bir DB'niz varsa, mevcut RAM'den çok daha büyük ve tüm DB'deki verilere rastgele dokunan erişim kalıpları varsa, dünyadaki tüm tampon havuzu ayarlaması size yardımcı olmaz. Verileri ve erişim kalıplarını anlarsanız, dikkatli bir tasarımla ağrının çoğunu hafifletebilirsiniz.
alanc10n

66

Oyuna biraz geç ... ama burada birkaç ay önce yazdığım ve MYISAM ile InnoDB arasındaki büyük farkları ayrıntılandıran oldukça kapsamlı bir yazı . Bir fincan (ve belki bir bisküvi) alın ve tadını çıkarın.


MyISAM ve InnoDB arasındaki en büyük fark referans bütünlüğü ve işlemleridir. Kilitleme, geri alma ve tam metin aramaları gibi başka farklar da vardır.

Bilgi tutarlılığı

Referans bütünlüğü, tablolar arasındaki ilişkilerin tutarlı kalmasını sağlar. Daha spesifik olarak, bu, bir tablonun (örn. Listeler) farklı bir tabloyu (örn. Ürünler) gösteren bir yabancı anahtarı (örn. Ürünler) olduğunda, sivri uçtaki tabloda güncellemeler veya silmeler meydana geldiğinde, bu değişikliklerin bağlantıya basamaklandırılması anlamına gelir tablo. Örneğimizde, bir ürün yeniden adlandırılırsa, bağlantı tablosunun yabancı anahtarları da güncellenir; bir ürün 'Ürünler' tablosundan silinirse, silinen girişe işaret eden tüm girişler de silinir. Ayrıca, her yeni girişte geçerli bir girişe işaret eden yabancı anahtar bulunmalıdır.

InnoDB ilişkisel bir DBMS'dir (RDBMS) ve bu nedenle referans bütünlüğü vardır, ancak MyISAM bunu yapmaz.

İşlemler ve Atomiklik

Tablodaki veriler, SELECT, INSERT, UPDATE ve DELETE gibi Veri İşleme Dili (DML) ifadeleri kullanılarak yönetilir. Bir işlem grubu iki veya daha fazla DML ifadesini tek bir iş biriminde bir araya getirir, böylece tüm birim uygulanır veya hiçbiri uygulanmaz.

MyISAM işlemleri desteklemezken InnoDB desteklemez.

Bir MyISAM tablosu kullanılırken bir işlem kesilirse, işlem derhal durdurulur ve etkilenen satırlar (hatta her satırdaki veriler) işlem tamamlanmasa bile etkilenmeye devam eder.

InnoDB tablosu kullanılırken bir işlem kesintiye uğrarsa, atomisitesi olan işlemler kullanması nedeniyle, tamamlanmayan herhangi bir işlem herhangi bir taahhüt yapılmadığından geçerli olmayacaktır.

Masa kilitleme ve Sıra kilitleme

Bir sorgu bir MyISAM tablosunda çalıştırıldığında, sorgulandığı tablonun tamamı kilitlenir. Bu, sonraki sorguların yalnızca geçerli sorgu bittikten sonra yürütüleceği anlamına gelir. Büyük bir tablo okuyorsanız ve / veya sık okuma ve yazma işlemleri varsa, bu büyük bir sorgu birikimi anlamına gelebilir.

Bir sorgu bir InnoDB tablosunda çalıştırıldığında, yalnızca ilgili satır (lar) kilitlenir, tablonun geri kalanı CRUD işlemleri için kullanılabilir durumda kalır. Bu, sorguların aynı satırı kullanmadıkları sürece aynı tabloda aynı anda çalışabileceği anlamına gelir.

InnoDB'deki bu özellik eşzamanlılık olarak bilinir. Eşzamanlılık ne kadar büyükse, belirli bir dizi tablo için geçerli olan büyük bir dezavantaj vardır, çünkü çekirdek iş parçacıkları arasında geçiş yapmada bir ek yük vardır ve sunucunun durmasını önlemek için çekirdek iş parçacıklarında bir sınır belirlemelisiniz. .

İşlemler ve Geri Alımlar

MyISAM içinde bir işlem çalıştırdığınızda, değişiklikler ayarlanır; InnoDB'de bu değişiklikler geri alınabilir. İşlemleri kontrol etmek için kullanılan en yaygın komutlar COMMIT, ROLLBACK ve SAVEPOINT'tir. 1. COMMIT - birden fazla DML işlemi yazabilirsiniz, ancak değişiklikler yalnızca bir COMMIT yapıldığında kaydedilir 2. ROLLBACK - henüz tamamlanmamış işlemleri iptal edebilirsiniz 3. SAVEPOINT - listesinde bir nokta belirler GERİ ALMA işleminin geri alınabileceği işlemler

Güvenilirlik

MyISAM hiçbir veri bütünlüğü sunmaz - Donanım hataları, temiz olmayan kapanmalar ve iptal edilen işlemler verilerin bozulmasına neden olabilir. Bu, dizinlerin ve tabloların tam olarak onarılmasını veya yeniden oluşturulmasını gerektirir.

InnoDB ise işlem bozulmalarını önlemek için işlem kaydı, çift yazma tamponu ve otomatik sağlama toplamı ve doğrulama kullanır. InnoDB herhangi bir değişiklik yapmadan önce, ibdata1 adlı bir sistem tablo alanı dosyasına işlemlerden önce verileri kaydeder. Bir kilitlenme olursa, InnoDB bu günlüklerin yeniden yürütülmesi yoluyla otomatik olarak yeniden bulur.

FULLTEXT Dizine Ekleme

InnoDB, MySQL sürüm 5.6.4'e kadar FULLTEXT dizinlemesini desteklemez. Bu gönderinin yazımı itibariyle, birçok paylaşılan barındırma sağlayıcısının MySQL sürümü hala 5.6.4'ün altındadır, bu da InnoDB tabloları için FULLTEXT dizinlemesinin desteklenmediği anlamına gelir.

Ancak, bu MyISAM'i kullanmak için geçerli bir neden değildir. MySQL'in güncel sürümlerini destekleyen bir barındırma sağlayıcısına geçmek en iyisidir. FULLTEXT dizinlemesi kullanan bir MyISAM tablosu, InnoDB tablosuna dönüştürülemez.

Sonuç

Sonuç olarak, InnoDB varsayılan depolama motorunuz olmalıdır. Belirli bir ihtiyaca hizmet ettiklerinde MyISAM veya diğer veri türlerini seçin.


Bir php oturumu sağlama toplamı komut dosyası yapıyordum ve anahtarımın çoğu [az09] 'un rastgele dizeleridir ... Innodb 30ms'yi aldı ve MyISAM'ı INSERT ON DUPLICATE KEY UPDATEdenedim ve şimdi <1ms'e düştü ... innodb'un 'kararsız' (rastgele dize) benzersiz anahtarlarla uğraşmakta zorlanıyor ... Bu konuda bizim için herhangi bir girdiniz var mı? Aslında MyISAM'ı kullanmak zorunda kalacağı etkiyi merak ediyordum ama harika cevabınız bu özel durum için gidilecek yol olduğunu anlamamı sağladı.
Louis Loudog Trottier

64

Daha fazla yazma ve okuma içeren bir yük için InnoDB'den yararlanacaksınız. InnoDB tablo kilitleme yerine sıra kilitleme sağladığı için, s'ler SELECTsadece birbirleriyle değil, aynı zamanda birçok INSERTs ile de eşzamanlı olabilir . Ancak, SQL işlemlerini kullanmak istemiyorsanız, InnoDB kesin sifonu 2 ( innodb_flush_log_at_trx_commit ) olarak ayarlayın. Bu, tabloları MyISAM'den InnoDB'ye taşıdığınızda kaybedeceğiniz çok fazla ham performans sağlar.

Ayrıca, çoğaltma eklemeyi de düşünün. Bu size bazı okuma ölçeklendirmeleri verir ve okumalarınızın güncel olması gerekmediğini belirttiğiniz için, çoğaltmanın biraz geride kalmasına izin verebilirsiniz. Sadece en yoğun trafik dışında bir şey yakalayabileceğinden emin olun, yoksa her zaman geride kalacaktır ve asla yetişmeyecektir. Ancak bu şekilde giderseniz , köleler ve çoğaltma gecikmesi yönetiminden veritabanı işleyicinize okumayı ayırmanızı önemle tavsiye ederim. Uygulama kodu bunu bilmiyorsa çok daha basittir.

Son olarak, farklı tabla yüklerinin farkında olun. Tüm tablolarda aynı okuma / yazma oranına sahip olmayacaksınız. Yaklaşık% 100 okumaya sahip bazı küçük tablolar MyISAM'da kalmayı göze alabilir. Benzer şekilde,% 100'e yakın yazma gibi bazı tablolarınız varsa, bundan yararlanabilirsiniz INSERT DELAYED, ancak bu yalnızca MyISAM'da desteklenir ( DELAYEDbir InnoDB tablosu için madde yok sayılır).

Ama emin olmak için kriter.


4
Bahsettiğiniz "InnoDB kesin sifonu" innodb_flush_log_at_trx_commitmu?
ceejayoz

2
Yayınınızı çok yararlı buldum - teşekkürler. Şu anda tablolarım ve yayınınız için MyISAM / InnoDB'nin ne zaman kullanılacağını değerlendirmek yardımcı oldu. Şerefe.
starmonkey

2
dev.mysql.com/doc/refman/5.5/tr/insert-delayed.html durumları: MyISAM tabloları için, veri dosyasının ortasında boş blok yoksa, eşzamanlı SELECT ve INSERT ifadeleri desteklenir. Bu koşullar altında, MyISAM ile GECİKMİŞ INSERT kullanmanız çok nadiren gerekir.
Timtam

Çok bilgilendirici yazı. Operasyonlarla aynı soruyu sordum ve yazınızın veritabanı motoru kararım hakkında beni rahatlattığını söylemeliyim. Teşekkürler! ++
Joe Majewski

Hızlı not: gecikmeli artık 5.7'de desteklenmemektedir. Bunun yerine LOW_PRIORITY ile test etmek isteyebilirsiniz.
webmat

59

Burada iki motor arasındaki mekanik farkları kapsayan geniş bir yelpazedeki yanıtlara eklemek için ampirik bir hız karşılaştırma çalışması sunuyorum.

Saf hız açısından, MyISAM'in InnoDB'den daha hızlı olması her zaman böyle değildir, ancak benim deneyimime göre, PURE READ çalışma ortamları için yaklaşık 2.0-2.5 kat daha hızlı olma eğilimindedir. Açıkçası bu tüm ortamlar için uygun değildir - diğerleri yazdığı gibi, MyISAM işlem ve yabancı anahtar gibi şeylerden yoksundur.

Aşağıda biraz kıyaslama yaptım - döngü için python ve zamanlama karşılaştırmaları için timeit kütüphanesini kullandım. İlgilenmek için, bellek motorunu da dahil ettim, bu sadece daha küçük tablolar için uygun olmasına rağmen ( The table 'tbl' is fullMySQL bellek sınırını aştığınızda sürekli karşılaşırsınız) bu kartta en iyi performansı verir . Baktığım dört seçim türü:

  1. vanilya SEÇİMLERİ
  2. sayımları
  3. koşullu SEÇİMLER
  4. indekslenmiş ve endekslenmemiş alt seçimler

İlk olarak, aşağıdaki SQL kullanarak üç tablo oluşturdum

CREATE TABLE
    data_interrogation.test_table_myisam
    (
        index_col BIGINT NOT NULL AUTO_INCREMENT,
        value1 DOUBLE,
        value2 DOUBLE,
        value3 DOUBLE,
        value4 DOUBLE,
        PRIMARY KEY (index_col)
    )
    ENGINE=MyISAM DEFAULT CHARSET=utf8

ikinci ve üçüncü tablolarda 'InnoDB' ve 'bellek' yerine 'MyISAM' kullanılır.

 

1) Vanilya seçer

Sorgu: SELECT * FROM tbl WHERE index_col = xx

Sonuç: çizmek

Vanilya seçimlerinin farklı veritabanı motorları ile karşılaştırılması

Bunların hızı genel olarak aynıdır ve beklendiği gibi seçilecek sütun sayısında doğrusaldır. InnoDB, MyISAM'den biraz daha hızlı görünüyor , ancak bu gerçekten marjinal.

Kod:

import timeit
import MySQLdb
import MySQLdb.cursors
import random
from random import randint

db = MySQLdb.connect(host="...", user="...", passwd="...", db="...", cursorclass=MySQLdb.cursors.DictCursor)
cur = db.cursor()

lengthOfTable = 100000

# Fill up the tables with random data
for x in xrange(lengthOfTable):
    rand1 = random.random()
    rand2 = random.random()
    rand3 = random.random()
    rand4 = random.random()

    insertString = "INSERT INTO test_table_innodb (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
    insertString2 = "INSERT INTO test_table_myisam (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
    insertString3 = "INSERT INTO test_table_memory (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"

    cur.execute(insertString)
    cur.execute(insertString2)
    cur.execute(insertString3)

db.commit()

# Define a function to pull a certain number of records from these tables
def selectRandomRecords(testTable,numberOfRecords):

    for x in xrange(numberOfRecords):
        rand1 = randint(0,lengthOfTable)

        selectString = "SELECT * FROM " + testTable + " WHERE index_col = " + str(rand1)
        cur.execute(selectString)

setupString = "from __main__ import selectRandomRecords"

# Test time taken using timeit
myisam_times = []
innodb_times = []
memory_times = []

for theLength in [3,10,30,100,300,1000,3000,10000]:

    innodb_times.append( timeit.timeit('selectRandomRecords("test_table_innodb",' + str(theLength) + ')', number=100, setup=setupString) )
    myisam_times.append( timeit.timeit('selectRandomRecords("test_table_myisam",' + str(theLength) + ')', number=100, setup=setupString) )
    memory_times.append( timeit.timeit('selectRandomRecords("test_table_memory",' + str(theLength) + ')', number=100, setup=setupString) )

 

2) Sayımlar

Sorgu: SELECT count(*) FROM tbl

Sonuç: MyISAM kazanır

Sayımların farklı veritabanı motorları ile karşılaştırılması

Bu MyISAM ve InnoDB arasındaki büyük farkı gösterir - MyISAM (ve bellek) tablodaki kayıt sayısını takip eder, bu nedenle bu işlem hızlı ve O (1) olur. InnoDB'nin sayması için gereken süre, araştırılan aralıktaki tablo boyutuyla süper doğrusal olarak artar. Uygulamada gözlemlenen MyISAM sorgularındaki hızlanmaların çoğunun benzer etkilerden kaynaklandığından şüpheleniyorum.

Kod:

myisam_times = []
innodb_times = []
memory_times = []

# Define a function to count the records
def countRecords(testTable):

    selectString = "SELECT count(*) FROM " + testTable
    cur.execute(selectString)

setupString = "from __main__ import countRecords"

# Truncate the tables and re-fill with a set amount of data
for theLength in [3,10,30,100,300,1000,3000,10000,30000,100000]:

    truncateString = "TRUNCATE test_table_innodb"
    truncateString2 = "TRUNCATE test_table_myisam"
    truncateString3 = "TRUNCATE test_table_memory"

    cur.execute(truncateString)
    cur.execute(truncateString2)
    cur.execute(truncateString3)

    for x in xrange(theLength):
        rand1 = random.random()
        rand2 = random.random()
        rand3 = random.random()
        rand4 = random.random()

        insertString = "INSERT INTO test_table_innodb (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
        insertString2 = "INSERT INTO test_table_myisam (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
        insertString3 = "INSERT INTO test_table_memory (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"

        cur.execute(insertString)
        cur.execute(insertString2)
        cur.execute(insertString3)

    db.commit()

    # Count and time the query
    innodb_times.append( timeit.timeit('countRecords("test_table_innodb")', number=100, setup=setupString) )
    myisam_times.append( timeit.timeit('countRecords("test_table_myisam")', number=100, setup=setupString) )
    memory_times.append( timeit.timeit('countRecords("test_table_memory")', number=100, setup=setupString) )

 

3) Koşullu seçimler

Sorgu: SELECT * FROM tbl WHERE value1<0.5 AND value2<0.5 AND value3<0.5 AND value4<0.5

Sonuç: MyISAM kazanır

Koşullu seçimlerin farklı veritabanı motorları ile karşılaştırılması

Burada, MyISAM ve bellek yaklaşık olarak aynı performansı gösterir ve daha büyük tablolar için InnoDB'yi yaklaşık% 50 yendi. Bu, MyISAM'in faydalarının en üst düzeye çıkarıldığı sorgu türüdür.

Kod:

myisam_times = []
innodb_times = []
memory_times = []

# Define a function to perform conditional selects
def conditionalSelect(testTable):
    selectString = "SELECT * FROM " + testTable + " WHERE value1 < 0.5 AND value2 < 0.5 AND value3 < 0.5 AND value4 < 0.5"
    cur.execute(selectString)

setupString = "from __main__ import conditionalSelect"

# Truncate the tables and re-fill with a set amount of data
for theLength in [3,10,30,100,300,1000,3000,10000,30000,100000]:

    truncateString = "TRUNCATE test_table_innodb"
    truncateString2 = "TRUNCATE test_table_myisam"
    truncateString3 = "TRUNCATE test_table_memory"

    cur.execute(truncateString)
    cur.execute(truncateString2)
    cur.execute(truncateString3)

    for x in xrange(theLength):
        rand1 = random.random()
        rand2 = random.random()
        rand3 = random.random()
        rand4 = random.random()

        insertString = "INSERT INTO test_table_innodb (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
        insertString2 = "INSERT INTO test_table_myisam (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
        insertString3 = "INSERT INTO test_table_memory (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"

        cur.execute(insertString)
        cur.execute(insertString2)
        cur.execute(insertString3)

    db.commit()

    # Count and time the query
    innodb_times.append( timeit.timeit('conditionalSelect("test_table_innodb")', number=100, setup=setupString) )
    myisam_times.append( timeit.timeit('conditionalSelect("test_table_myisam")', number=100, setup=setupString) )
    memory_times.append( timeit.timeit('conditionalSelect("test_table_memory")', number=100, setup=setupString) )

 

4) Alt seçimler

Sonuç: InnoDB kazanır

Bu sorgu için, alt seçim için ek bir tablo kümesi oluşturdum. Her biri, biri birincil anahtar dizini ve diğeri dizini olmayan iki BIGINT sütunu. Büyük masa boyutu nedeniyle, bellek motorunu test etmedim. SQL tablo oluşturma komutu

CREATE TABLE
    subselect_myisam
    (
        index_col bigint NOT NULL,
        non_index_col bigint,
        PRIMARY KEY (index_col)
    )
    ENGINE=MyISAM DEFAULT CHARSET=utf8;

burada bir kez daha, 'MyISAM' ikinci tabloda 'InnoDB' ile değiştirilir.

Bu sorguda, seçim tablosunun boyutunu 1000000'de bırakıyorum ve bunun yerine alt seçili sütunların boyutunu değiştiriyorum.

Alt veritabanı seçimlerinin farklı veritabanı motorları ile karşılaştırılması

Burada InnoDB kolayca kazanır. Makul bir boyut tablosuna ulaştıktan sonra her iki motor da alt seçimin boyutu ile doğrusal olarak ölçeklenir. Dizin MyISAM komutunu hızlandırır, ancak ilginç bir şekilde InnoDB hızı üzerinde çok az etkisi vardır. subSelect.png

Kod:

myisam_times = []
innodb_times = []
myisam_times_2 = []
innodb_times_2 = []

def subSelectRecordsIndexed(testTable,testSubSelect):
    selectString = "SELECT * FROM " + testTable + " WHERE index_col in ( SELECT index_col FROM " + testSubSelect + " )"
    cur.execute(selectString)

setupString = "from __main__ import subSelectRecordsIndexed"

def subSelectRecordsNotIndexed(testTable,testSubSelect):
    selectString = "SELECT * FROM " + testTable + " WHERE index_col in ( SELECT non_index_col FROM " + testSubSelect + " )"
    cur.execute(selectString)

setupString2 = "from __main__ import subSelectRecordsNotIndexed"

# Truncate the old tables, and re-fill with 1000000 records
truncateString = "TRUNCATE test_table_innodb"
truncateString2 = "TRUNCATE test_table_myisam"

cur.execute(truncateString)
cur.execute(truncateString2)

lengthOfTable = 1000000

# Fill up the tables with random data
for x in xrange(lengthOfTable):
    rand1 = random.random()
    rand2 = random.random()
    rand3 = random.random()
    rand4 = random.random()

    insertString = "INSERT INTO test_table_innodb (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
    insertString2 = "INSERT INTO test_table_myisam (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"

    cur.execute(insertString)
    cur.execute(insertString2)

for theLength in [3,10,30,100,300,1000,3000,10000,30000,100000]:

    truncateString = "TRUNCATE subselect_innodb"
    truncateString2 = "TRUNCATE subselect_myisam"

    cur.execute(truncateString)
    cur.execute(truncateString2)

    # For each length, empty the table and re-fill it with random data
    rand_sample = sorted(random.sample(xrange(lengthOfTable), theLength))
    rand_sample_2 = random.sample(xrange(lengthOfTable), theLength)

    for (the_value_1,the_value_2) in zip(rand_sample,rand_sample_2):
        insertString = "INSERT INTO subselect_innodb (index_col,non_index_col) VALUES (" + str(the_value_1) + "," + str(the_value_2) + ")"
        insertString2 = "INSERT INTO subselect_myisam (index_col,non_index_col) VALUES (" + str(the_value_1) + "," + str(the_value_2) + ")"

        cur.execute(insertString)
        cur.execute(insertString2)

    db.commit()

    # Finally, time the queries
    innodb_times.append( timeit.timeit('subSelectRecordsIndexed("test_table_innodb","subselect_innodb")', number=100, setup=setupString) )
    myisam_times.append( timeit.timeit('subSelectRecordsIndexed("test_table_myisam","subselect_myisam")', number=100, setup=setupString) )

    innodb_times_2.append( timeit.timeit('subSelectRecordsNotIndexed("test_table_innodb","subselect_innodb")', number=100, setup=setupString2) )
    myisam_times_2.append( timeit.timeit('subSelectRecordsNotIndexed("test_table_myisam","subselect_myisam")', number=100, setup=setupString2) )

Tüm bunların eve dönüş mesajı, hız konusunda gerçekten endişeleniyorsanız, hangi motorun daha uygun olacağına dair herhangi bir varsayım yapmak yerine yaptığınız sorguları karşılaştırmanız gerektiğidir.


1
performans her zaman tek düşüncedir, istikrar hakkında bir grafiğe ne dersiniz? bir motor çökerse ve temel veritabanı özelliklerini desteklemiyorsa hiçbir şey için iyi değildir.
pilavdzice

1
my.cnfDosya InnoDB için optimize edilmemişse MyISAM muhtemelen InnoDB'yi çoğu zaman yener . my.cnfDosyanızın nasıl göründüğünden bahsetmediniz , bu InnoDB performansı için gerçekten en önemli faktördür.
itoctopus

Teşekkürler itoctopus - Önerdiğiniz optimizasyonlar hakkında daha fazla bilgi almak isterim. Bu testlerde kullanılan tam kod yukarıda, deneyleri çeşitli optimizasyonlarla tekrarlamaktan çekinmeyin ve sonuçlarda önemli değişiklikler bulursanız bize bildirin
StackG

32

Biraz konu dışı, ancak dokümantasyon amaçları ve bütünlük için aşağıdakileri eklemek istiyorum.

Genel olarak InnoDB kullanımı, muhtemelen daha fazla hatasız, çok daha az karmaşık bir uygulama ile sonuçlanacaktır. Tüm referans bütünlüğünü (Yabancı Anahtar kısıtlamaları) veri modeline koyabildiğiniz için, MyISAM ile ihtiyaç duyduğunuz kadar uygulama koduna yakın bir yere ihtiyacınız yoktur.

Her kayıt eklediğinizde, sildiğinizde veya değiştirdiğinizde, ilişkileri kontrol etmeniz ve sürdürmeniz GEREKİR. Örneğin bir ebeveyni silerseniz, tüm çocuklar da silinmelidir. Örneğin, basit bir blog sisteminde bile, bir blog yazısı kaydını silerseniz, yorum kayıtlarını, beğenileri vb. Silmeniz gerekir. InnoDB'de bu, veritabanı motoru tarafından otomatik olarak yapılır (modeldeki çelişkileri belirttiyseniz) ) ve uygulama kodu gerektirmez. MyISAM'de bunun web sunucularında çok zor olan uygulamaya kodlanması gerekecektir. Web sunucuları doğası gereği çok eşzamanlı / paraleldir ve bu eylemlerin atomik olması gerektiğinden ve MyISAM hiçbir gerçek işlemi desteklemediğinden, web sunucuları için MyISAM kullanımı riskli / hataya açıktır.

Ayrıca, çoğu genel durumda, InnoDB, birçok nedenden ötürü, daha iyi performans gösterecektir, bunlardan biri, tablo düzeyinde kilitlemenin aksine kayıt seviyesi kilitlemeyi kullanabilmektedir. Sadece yazıların okumadan daha sık olduğu bir durumda değil, aynı zamanda büyük veri kümelerinde karmaşık birleşme olan durumlarda da. Çok büyük birleşimler için (birkaç dakika süren) MyISAM tabloları üzerinde sadece InnoDB tablolarını kullanarak 3 kat performans artışı fark ettik.

Genel olarak InnoDB (referans bütünlüğü ile tam bir 3NF datamodel kullanarak) MySQL kullanırken varsayılan seçim olması gerektiğini söyleyebilirim. MyISAM yalnızca çok özel durumlarda kullanılmalıdır. Büyük olasılıkla daha az performans gösterecek, daha büyük ve daha buggy bir uygulama ile sonuçlanacaktır.

Bunu söylerken. Datamodelling, web tasarımcıları / programcıları arasında nadiren bulunan bir sanattır. Suç yok, ama MyISAM'ın bu kadar çok kullanıldığını açıklıyor.


31

InnoDB şunları sunar:

ACID transactions
row-level locking
foreign key constraints
automatic crash recovery
table compression (read/write)
spatial data types (no spatial indexes)

InnoDB'de TEXT ve BLOB dışındaki tüm veriler en fazla 8.000 bayt kaplayabilir. InnoDB için tam metin indeksleme yok. InnoDB'de, COUNT (*) s (WHERE, GROUP BY veya JOIN kullanılmadığında) satır sayısı dahili olarak saklanmadığından MyISAM'den daha yavaş yürütülür. InnoDB hem verileri hem de dizinleri tek bir dosyada saklar. InnoDB, hem verileri hem de dizinleri önbelleğe almak için bir tampon havuzu kullanır.

MyISAM şunları sunar:

fast COUNT(*)s (when WHERE, GROUP BY, or JOIN is not used)
full text indexing
smaller disk footprint
very high table compression (read only)
spatial data types and indexes (R-tree)

MyISAM tablo düzeyinde kilitlemeye sahiptir, ancak satır düzeyinde kilit yoktur. İşlem yok. Otomatik çökme kurtarma yok, ancak onarım tablosu işlevselliği sunuyor. Yabancı anahtar kısıtlaması yok. MyISAM tabloları genellikle InnoDB tablolarına kıyasla disk üzerinde daha küçük boyutludur. MyISAM tabloları, gerekirse myisampack ile sıkıştırılarak daha da büyük ölçüde azaltılabilir, ancak salt okunur hale gelebilir. MyISAM, dizinleri bir dosyada ve verileri başka bir dosyada saklar. MyISAM, dizinleri önbelleğe almak için anahtar arabellekleri kullanır ve veri önbellek yönetimini işletim sistemine bırakır.

Genel olarak InnoDB çoğu amaç için ve MyISAM yalnızca özel kullanımlar için tavsiye ederim. InnoDB artık yeni MySQL sürümlerinde varsayılan motor.


2
fwiw, InnoDB'deki VARCHAR, BLOB ve TEXT gibi taşma sayfalarına da gidebilir. Tüm bu veri türleri benzer şekilde dahili olarak saklanır.
Bill Karwin

Bilmek güzel, @ BillKarwin! Biz bizim app VARCHAR yoğun kullanın ve VARCHAR bu ~ 8kB sınır katkıda katkıda bulunmak biraz ilgiliydi.
rinogo


günümüzde MySQL sürüm 5.6 ve sonraki sürümlerinde innodb motoru artık tam metin dizine eklemeyi ve MySQL 5.5 + / 5.7 + da uzamsal veri türlerini (5.5+) ve uzamsal dizinleri (r-tee) (5.7+) desteklemektedir. .. En iyi destek için en azından MySQL sürüm 5.7+ sürümüne sahip olmanız gerekir
Raymond Nijland

25

MyISAM kullanıyorsanız, her DML ifadesini bir işlem olarak görmediğiniz sürece saatte herhangi bir işlem yapmayacaksınız (her durumda kilitlenme durumunda dayanıklı veya atomik olmayacaktır).

Bu nedenle InnoDB'yi kullanmanız gerektiğini düşünüyorum.

Saniyede 300 işlem oldukça fazla gibi geliyor. Bu işlemlerin elektrik kesintisi boyunca kalıcı olması için kesinlikle ihtiyacınız varsa, G / Ç alt sisteminizin saniyede bu kadar çok yazma işlemini kolayca yapabildiğinden emin olun. Pil destekli önbelleğe sahip en az bir RAID denetleyicisine ihtiyacınız olacaktır.

Küçük bir dayanıklılık isabeti alabilirseniz, innodb_flush_log_at_trx_commit 0 veya 2 olarak ayarlanmış olarak InnoDB'yi kullanabilirsiniz (ayrıntılar için belgelere bakın), performansı artırabilirsiniz.

Google'dan ve diğerlerinden eşzamanlılığı artırabilecek bir dizi yama var - bunlar olmadan hala yeterli performans alamıyorsanız bunlar ilgi çekici olabilir.


24

Soru ve Yanıtların çoğu güncel değil .

Evet, MyISAM'ın InnoDB'den daha hızlı olması eski bir eşlerin hikayesi. Sorunun tarihine dikkat edin: 2008; neredeyse on yıl sonra. InnoDB, o zamandan beri önemli performans adımları attı.

Dramatik grafik, MyISAM'ın kazandığı tek durum içindi: bir madde COUNT(*) olmadanWHERE . Ama bu gerçekten zamanınızı harcadığınız şey mi?

Eşzamanlılık testi yaparsanız , InnoDB'nin bile karşısındaMEMORY kazanma olasılığı çok yüksektir .

Kıyaslama yaparken herhangi bir yazma yaparsanız SELECTs, MyISAM ve MEMORYtablo düzeyinde kilitleme nedeniyle kaybedilmesi muhtemeldir.

Aslında, Oracle InnoDB'nin MyISAM'ı 8.0'dan kaldırmış olanlardan daha iyi olduğundan emin.

Soru erken 5.1 günlerinde yazılmış. O zamandan beri, bu ana sürümler "Genel Kullanılabilirlik" olarak işaretlendi:

  • 2010: 5.5 (Aralık ayında .8)
  • 2013: 5,6 (Şubat'ta 0,10)
  • 2015: 5.7 (Ekim ayında .9)
  • 2018: 8.0 (Nisan'da 0,11)

Alt satır: MyISAM kullanma


2
MySQL veritabanı teknolojisi gelişiyor. Ve StackOverflow soru ve cevapları geçmişte kalmış durumda. Ana MyISAM ve InnoDB arasındaki farklar daha az sunucuda "yük" hakkında ve daha desteği hakkında referans bütünlüğü ve işlemlerin yanı sıra eşzamanlılık ve kazanılabilirliği (10)
spencer7593

12

Ayrıca MySQL'in kendisi için bazı bırakma yedeklerine de göz atın:

mariadb

http://mariadb.org/

MariaDB, MySQL için yedek değiştirme işlevselliği sunan bir veritabanı sunucusudur. MariaDB, MySQL'in bazı orijinal yazarları tarafından, daha geniş Ücretsiz ve açık kaynak yazılım geliştiricileri topluluğunun yardımıyla inşa edilmiştir. MySQL'in temel işlevlerine ek olarak MariaDB, alternatif depolama motorları, sunucu optimizasyonları ve yamalar gibi zengin bir dizi özellik geliştirmesi sunar.

Percona Sunucusu

https://launchpad.net/percona-server

Daha iyi performans, gelişmiş tanılama ve ek özelliklerle MySQL için geliştirilmiş bir bırakma değiştirme.


1
İkisini de kullanıyorum (üretimde Percona, pencere geliştirme konusunda Maria). daha hızlıdırlar ve mükemmel çalışırlar.
Moshe L

4
Bu soruya cevap vermiyor. MariaDB ve Percona, MySQL'in çatallarıdır ve InnoDB ve MyISAM motorlarını da kullanır.
dr_

12

Resmi eğitimimin ve deneyimimin Oracle ile olduğunu lütfen unutmayın , MySQL ile çalışmam tamamen kişisel ve kendi zamanımdayken, Oracle için doğru olan ancak MySQL için doğru olmayan şeyler söylersem özür dilerim. İki sistem çok paylaşsa da, ilişkisel teori / cebir aynıdır ve ilişkisel veritabanları hala ilişkisel veritabanlarıdır, yine de birçok farklılık vardır !!

Özellikle InnoDB işlem tabanlı olduğu gibi (satır düzeyinde kilitleme gibi), web uygulamanızın bir "operasyon" için birkaç kez güncelleme / ekleme / oluşturma / değiştirme / bırakma / vb. Ortaya çıkan sorun , bu değişikliklerin / işlemlerin sadece bir kısmının işlenmesi, ancak diğerlerinin başlamaması durumunda, çoğu zaman (veritabanının özel tasarımına bağlı olarak) çakışan veri / yapıya sahip bir veritabanı ile sonuçlanmanızdır.

Not: Oracle ile create / alter / drop ifadeleri "DDL" (Veri Tanımı) ifadeleri olarak adlandırılır ve dolaylı olarak bir taahhüdü tetikler. Ekle / güncelleme / silme ifadeleri, sözde "DML" (veri düzenleme), vardır değil otomatik kalmaz, ancak DDL, taahhüt veya çıkış / gerçekleştirilir bıraktım sadece (veya "otomatik tamamlama" için oturumu ayarlarsanız, ya müşteriniz otomatik olarak işliyorsa). Oracle ile çalışırken bunun farkında olmak zorunludur, ancak MySQL'in iki tür ifadeyi nasıl işlediğinden emin değilim. Bu nedenle, MySQL söz konusu olduğunda bundan emin olmadığımı açıklığa kavuşturmak istiyorum; yalnızca Oracle ile.

İşlem tabanlı motorların ne zaman başarılı olduğunu gösteren bir örnek:

Diyelim ki ben veya siz, ücretsiz bir etkinliğe katılmak için kaydolmak üzere bir web sayfasındasınız ve sistemin temel amaçlarından biri, yalnızca 100 kişiye kaydolmaya izin vermektir, çünkü bu, oturma sınırıdır. Etkinlik için. 100 kayda ulaşıldığında, sistem en azından diğerleri iptal edilene kadar başka kayıtları devre dışı bırakır.

Bu durumda, konuklar için bir tablo (ad, telefon, e-posta vb.) Ve kaydolan konuk sayısını izleyen ikinci bir tablo olabilir. Böylece bir "işlem" için iki operasyonumuz var. Şimdi konuk bilgileri MİSAFİRLER tablosuna eklendikten sonra, bir bağlantı kaybı veya aynı etkiye sahip bir hata olduğunu varsayalım. GUESTS tablosu güncellendi (içine eklendi), ancak "kullanılabilir koltuklar" güncellenmeden önce bağlantı kesildi.

Şimdi konuk masasına bir konuk ekledik, ancak mevcut koltuk sayısı artık yanlış (örneğin, gerçekte 84 olduğunda değer 85'tir).

Tabii ki bunu işlemek için birçok yol vardır, örneğin "konuklar tablosunda 100 eksi satır sayısı" ile mevcut koltukları izleme veya bilgilerin tutarlı olup olmadığını kontrol eden bir kod, vb .... Ama işlem tabanlı bir veritabanı ile InnoDB gibi motorlar, ya TÜM işlemler yapılır ya da HİÇBİRİ yapılmaz . Bu birçok durumda yardımcı olabilir, ancak dediğim gibi, güvenli olmanın SADECE yolu değil, hayır (ancak, programcı / senaryo yazarı değil, veritabanı tarafından ele alınmanın iyi bir yolu).

Bir şey eksik olmadıkça, tüm "işlem tabanlı" temelde bu bağlamda anlamına gelir - ya tüm işlem olması gerektiği gibi başarılı olur ya da hiçbir şey değiştirilmez, çünkü sadece kısmi değişiklikler yapmak, SEVERE karmaşasını küçük bir hale getirebilir veritabanı, belki de bozuyor ...

Ama bir kez daha söyleyeceğim, karışıklıktan kaçınmanın tek yolu bu değil. Ancak, motorun kendisinin işlediği yöntemlerden biridir, sizi endişelenmeye gerek kalmadan kod / betiğe bırakarak "işlem başarılı ya da başarılı değildi ve elimde değilse (yeniden denemek gibi) ne yapmalıyım? veritabanının dışından "elle" kontrol etmek için kod yazma ve bu tür etkinlikler için çok daha fazla iş yapma.

Son olarak, tablo kilitleme ve satır kilitleme hakkında bir not:

YASAL UYARI: MySQL ile ilgili olarak takip eden her şeyde yanlış olabilirim ve varsayımsal / örnek durumlar göz önünde bulundurulması gereken şeylerdir, ancak MySQL ile yolsuzluğa yol açmanın tam olarak mümkün olabileceği konusunda yanlış olabilirim. Bununla birlikte, örnekler MySQL'in bu tür şeylerden kaçınmak için daha fazla mekanizması olsa bile genel programlamada çok gerçek ...

Neyse, ben bir anda izin kaç bağlantı iddia edenler ile kabul oldukça eminim gelmez değil kilitli tablo geçici. Aslında, birden fazla bağlantı bir tablo kilitlemenin tüm noktasıdır !! Böylece diğer işlemler / kullanıcılar / uygulamalar aynı anda değişiklik yaparak veritabanını bozamaz.

Aynı satırda çalışan iki veya daha fazla bağlantı sizin için GERÇEKTEN KÖTÜ BİR GÜN yapar? Diyelim ki, aynı satırda aynı değeri güncellemek isteyen / gereken iki işlem var, diyelim ki satır bir otobüs turunun kaydı ve iki işlemin her biri aynı anda "binicileri" veya "available_seats" i güncellemek istiyor alanına "geçerli değer artı 1"

Bunu varsayımsal olarak adım adım yapalım:

  1. Birinci işlem mevcut değeri okur, diyelim ki boş, bu yüzden şimdiye kadar '0'.
  2. İkinci işlem mevcut değeri de okur, ki bu hala 0'dır.
  3. Birinci işlem 1 (mevcut + 1) yazar.
  4. İkinci işlem 2 yazmalıdır , ancak işlemden önce geçerli değeri okuduğundan yeni değeri yazdığından, tabloya da 1 yazar.

İki bağlantının bu şekilde karışabileceğinden emin değilim , her ikisi de birincisi yazmadan önce okuma ... Ama eğer değilse, o zaman hala bir sorun görecektim:

  1. Birinci işlem, 0 olan geçerli değeri okur.
  2. Birinci işlem yazıyor (güncel + 1), yani 1.
  3. İkinci işlem şimdi geçerli değeri okur. Ancak bir DID yazma işlemi (güncelleme) yapılırken, verileri işlemedi, bu yüzden sadece aynı süreç güncellenen yeni değeri okuyabilirken, diğerleri bir taahhüt olana kadar daha eski değeri görebilir.

Ayrıca, en azından Oracle veritabanlarında, yorumlamaya çalışırken zamanımızı boşa harcamadığım izolasyon seviyeleri var. İşte bu konuda iyi bir makale ve işlem tabanlı motorların bir veritabanında ne kadar önemli olabileceğiyle birlikte artıları ve eksileri olan her yalıtım seviyesi ...

Son olarak, MyISAM içinde yabancı anahtarlar ve işleme dayalı etkileşim yerine farklı güvenceler olabilir. Birincisi, tüm bir tablonun kilitli olduğu gerçeği vardır, bu da işlemlere / FK'lere ihtiyaç duyma olasılığını azaltır .

Ne yazık ki, bu eşzamanlılık sorunlarının farkındaysanız, evet daha az güvenli oynayabilir ve sadece uygulamalarınızı yazabilir, sistemlerinizi bu tür hataların mümkün olmayacağı şekilde ayarlayabilirsiniz (kodunuz veritabanının kendisinden ziyade sorumludur). Bununla birlikte, bence, mümkün olduğunca çok sayıda koruma kullanmanın, savunmacı bir şekilde programlama yapmanın ve insan hatasının tamamen önlenmesinin imkansız olduğunun farkında olmanın her zaman en iyisi olduğunu söyleyebilirim. Herkesin başına gelir ve ona karşı bağışık olduklarını söyleyen herkes yalan söylemeli veya bir "Merhaba Dünya" uygulaması / komut dosyası yazmaktan daha fazlasını yapmamış olmalıdır. ;-)

Umarım BAZI bazıları için yararlıdır, ve daha da fazlası, umarım şimdi sadece varsayımların bir suçlu olmadım ve yanlışlıkla bir insan olmadım! Öyleyse özür dilerim, ancak örnekler bu bağlamda potansiyel olmasa bile düşünmek, riskini araştırmak vb. İçin iyidir.

Beni düzeltmekten çekinmeyin, bu "cevabı" düzenleyin, hatta oy verin. Sadece kötü bir varsayımı bir başkasıyla düzeltmek yerine geliştirmeye çalışın. ;-)

Bu benim ilk cevabım, bu yüzden lütfen tüm feragatnameler, vb. Nedeniyle uzunluğu affedin ... Kesinlikle emin olmadığımda kibirli görünmek istemiyorum!



5

Deneyimlerime göre, SİLME, GÜNCELLEME, bir sürü tek INSERT, işlemler ve tam metin dizinleme yapmadığınız sürece MyISAM daha iyi bir seçim oldu. BTW, KONTROL TABLOSU korkunç. Tablo satır sayısı açısından yaşlandıkça, ne zaman sona ereceğini bilmiyorsunuz.


2
Tam metin dizine ekleme yalnızca MyISAM ile mümkündür, InnoDB ile mümkün değildir.
Pixel Elephant

2
@PixelElephant, bu MySQL 5.6'da değişmeye başlıyor. InnoDB bir tam metin dizin türüne sahiptir, ancak şu ana kadar IMHO'nun üretim kullanımına hazır değildir.
Bill Karwin

1
“Tam metin indeksleme InnoDB ile değil, sadece MyISAM ile mümkündür”: MySQL> = 5.6 olduğundan artık doğru değil. Bkz. Dev.mysql.com/doc/refman/5.6/en/fulltext-search.html .
Hibou57

5

Myisam'ın kilitli çekişme olmasına rağmen, kullandığı hızlı kilit alma şeması nedeniyle çoğu senaryoda InnoDb'den daha hızlı olduğunu anladım. Birkaç kez Innodb denedim ve her zaman MyIsam için bir nedenden ötürü düşmek. Ayrıca InnoDB büyük yazma yüklerinde çok CPU yoğun olabilir.


4

Her uygulamanın bir veritabanı kullanmak için kendi performans profili vardır ve zaman içinde değişme olasılığı vardır.

Yapabileceğiniz en iyi şey seçeneklerinizi test etmektir. MyISAM ve InnoDB arasında geçiş yapmak son derece önemlidir, bu nedenle sitenize bazı test verileri ve yangın ölçer yükleyin ve neler olduğunu görün.


4

MyISAM ve InnoDB tablolarına rastgele veri eklenmesini çalıştırmayı denedim. Sonuç oldukça şok ediciydi. MyISAM, InnoDB'den sadece 10 bin 1 milyon satır eklemek için birkaç saniyeye daha az ihtiyaç duyuyordu!


2
İşlemi kullanır ve InnoDB motoru için otomatik taahhüdü kapatırsanız aynı performansı elde edersiniz.
stanleyxu2005

IDK aynı performansa sahipse, ancak daha karmaşık uygulamalarda yaptığım şey bu ve bunu hızlandırıyor.
user965748

1
Denemenizin tam ayrıntılarını sağlayamadınız - hangi yapılandırma ayarları? Daha önce tablolarda neler vardı? Ne tür veriler? ve belki de en önemlisi - sıralı uçlar var mıydı? Paralel? Zamanlamaları neydi? Kaç CPU çekirdeği? İş Parçacığı? vs.
einpoklum

3

myisam bu tür bir iş yükü için bir NOGO (yüksek eşzamanlılık yazar), ben innodb ile çok fazla deneyime sahip değilim (3 kez test edildi ve her durumda performansın emildiğini buldum, ancak son testten bu yana bir süre geçti) mysql çalıştırmak zorunda değilsiniz, aynı anda çok daha iyi yazıyor gibi postgres deneyin deneyin


3

Kısacası, birçok INSERT ve UPDATE talimatını işleyebilecek güvenilir bir veritabanına ihtiyaç duyan bir şey üzerinde çalışıyorsanız InnoDB iyidir.

ve MyISAM, tablo kilidi konusundaki dezavantajı göz önünde bulundurarak, yazma (INSERT ve UPDATES) yerine çoğunlukla çok fazla okuma (SELECT) talimatı alacak bir veritabanına ihtiyacınız varsa iyidir.

kontrol etmek isteyebilirsiniz;
InnoDB
Artıları ve Eksileri MyISAM Artıları ve Eksileri


2

Bunun popüler olmayacağını biliyorum ama işte gidiyor:

myISAM, genellikle glitchy / buggy uygulamalarıyla sonuçlanan işlemler ve referans bütünlüğü gibi veritabanı temelleri için desteğe sahip değildir. Eğer db motorunuz tarafından desteklenmiyorsa, uygun veritabanı tasarımı temellerini öğrenemezsiniz.

Veritabanı dünyasında bilgi bütünlüğü veya işlemleri kullanmamak, yazılım dünyasında nesne yönelimli programlama kullanmamak gibidir.

InnoDB şimdi var, bunu kullanın! Hatta MySQL geliştiricileri, myISAM'ın tüm eski sistemlerde varsayılan orijinal motor olmasına rağmen, bunu daha yeni sürümlerde varsayılan motor olarak değiştirmeyi kabul ettiler.

Hayır, okuma veya yazma veya performans performansınız ne olursa olsun, myISAM'ı kullanmak gibi çeşitli sorunlara neden olabilir, bununla karşılaştım: Bir veritabanı senkronizasyonu yapıyordum ve aynı zamanda başka biri myISAM için ayarlanmış bir tabloya erişen bir uygulamaya erişti. İşlem desteği eksikliği ve bu motorun genellikle zayıf güvenilirliği nedeniyle, bu tüm veritabanını çöktü ve mysql'yi manuel olarak yeniden başlatmak zorunda kaldım!

Gelişimin son 15 yılında, birçok veritabanı ve motor kullandım. myISAM bu süre zarfında bir düzine kez daha çöktü, diğer veritabanları, sadece bir kez! Ve bu, bazı geliştiricilerin hatalı CLR kodu (ortak dil çalışma zamanı - temelde veritabanı içinde çalışan C # kodu) yazdığı bir microsoft SQL veritabanı idi, bu tam olarak veritabanı motorunun hatası değildi.

Buradaki diğer cevaplara katılıyorum, kaliteli yüksek kullanılabilirlikli, yüksek performanslı uygulamaların myISAM'ı işe yaramayacağı için kullanmaması gerektiğini, hayal kırıklığı yaratmayan bir deneyimle sonuçlanacak kadar sağlam veya kararlı olmadığını söylüyor. Daha fazla bilgi için Bill Karwin'in cevabına bakınız.

PS, myISAM fanatiği düştüğünde onu sevmeli ama bu cevabın hangi bölümünün yanlış olduğunu söyleyemez.


5
Ben downvote vermedi, ama yapsaydım asla kullanmak tavsiye için olurdu. kelime asla bir geliştiricinin kelime hazinesi vurulmamalıdır ... uyarı 'asla asla deme' olmak.
hubson bropa

1

Bu okuma / yazma oranı için InnoDB daha iyi performans sanırım. Kirli okumalarla iyi olduğunuz için, (eğer karşılarsanız) bir köleye çoğaltabilir ve tüm okumalarınızın köleye gitmesine izin verebilirsiniz. Ayrıca, bir kerede bir kayıt yerine toplu olarak eklemeyi düşünün.


1

Neredeyse her yeni projeye başladığımda, aynı soruyu Google'a yeni bir cevap bulup bulmadığımı görmek için de aynı soruyu soruyorum.

Sonunda kaynar - MySQL'in en son sürümünü alıp testleri çalıştırıyorum.

Anahtar / değer aramaları yapmak istediğim tablolarım var ... ve hepsi bu. Bir karma anahtarı için değer (0-512 bayt) almak gerekiyor. Bu DB'de çok fazla işlem yok. Tablo zaman zaman güncellemeler alır (tamamen), ancak 0 işlem.

Bu yüzden burada karmaşık bir sistemden bahsetmiyoruz, basit bir aramadan bahsediyoruz, .. ve (masa RAM'inin yerleşik olmasını sağlamak dışında) performansı nasıl optimize edebileceğimizden bahsediyoruz.

Ben de bir avantaj elde edebilirsiniz herhangi bir yerde olup olmadığını görmek için diğer veritabanlarında (yani NoSQL) testleri yapmak. Bulduğum en büyük avantaj anahtar haritalamada ancak arama ilerledikçe, MyISAM şu anda hepsini tamamlıyor.

Gerçi, MyISAM tabloları ile finansal işlemler yapmazdım ama basit aramalar için test etmelisiniz.

Test et, tartışmaya açığım.


1

% 70 ekler ve% 30 okuyorsa, InnoDB tarafında olduğu gibi.


0

alt satır: büyük veri yığınlarında seçimlerle çevrimdışı çalışıyorsanız, MyISAM muhtemelen size daha iyi (çok daha iyi) hızlar verecektir.

MyISAM'ın InnoDB'den çok daha verimli olduğu bazı durumlar vardır: büyük veri dökümlerini çevrimdışı olarak (tablo kilidi nedeniyle) değiştirirken.

örnek: Anahtar olarak VARCHAR alanlarını kullanan NOAA'dan bir csv dosyasını (15M kayıtları) dönüştürüyordum. InnoDB, büyük bellek parçaları olsa bile sonsuza dek sürüyordu.

bu bir csv örneğidir (birinci ve üçüncü alanlar anahtardır).

USC00178998,20130101,TMAX,-22,,,7,0700
USC00178998,20130101,TMIN,-117,,,7,0700
USC00178998,20130101,TOBS,-28,,,7,0700
USC00178998,20130101,PRCP,0,T,,7,0700
USC00178998,20130101,SNOW,0,T,,7,

ne yapmam gerektiğini gözlemlenen hava olayları toplu çevrimdışı güncelleme çalıştırmak olduğundan, ben gelen dosyayı temizlemek ve VARCHAR alanları INT tuşları (ki ilgili orijinal VARCHAR değerlerinin depolandığı harici tablolar).

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.