MySQL'de kilitlemeye neden olmadan seçmenin bir yolu var mı?


126

Sorgu:

SELECT COUNT(online.account_id) cnt from online;

Ancak çevrimiçi tablo da bir olay tarafından değiştirildi, bu yüzden sık sık çalıştırarak kilidi görebiliyorum show processlist.

MySQL'de select deyiminin kilitlere neden olmamasını sağlayabilecek herhangi bir dilbilgisi var mı?

Ve yukarıda bunun bir MySQL köle veri tabanında olduğunu söylemeyi unuttum.

my.cnf:transaction-isolation = READ-UNCOMMITTED Slave'e ekledikten sonra hata ile karşılaşacak:

Hata 'İkili kayıt mümkün değil. İleti: InnoDB'deki işlem düzeyi 'OKUMA-GERÇEKLEŞTİRİLDİ', sorguda binlog modu 'STATEMENT' için güvenli değil

Peki, bunu yapmanın uyumlu bir yolu var mı?


3
Bu soruyla karşılaşan ve masalarındaki kilitlerle zor anlar yaşayan diğerleri için: mySQL'in kilitleri dahili olarak nasıl kullandığı, depolama motoruna bağlıdır. Cevabı aşağıda @zombat tarafından okuyun.
Simon Forsberg

Yanıtlar:


169

"NOLOCK İLE MYSQL" başlıklı bir makale buldum

https://web.archive.org/web/20100814144042/http://sqldba.org/articles/22-mysql-with-nolock.aspx

MS SQL Server'da aşağıdakileri yaparsınız:

SELECT * FROM TABLE_NAME WITH (nolock)

ve MYSQL eşdeğeri

SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;
SELECT * FROM TABLE_NAME ;
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ ;

DÜZENLE

Michael Mior aşağıdakileri önerdi (yorumlardan)

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;
SELECT * FROM TABLE_NAME ;
COMMIT ;

54
Gelecekteki okuyuculara, ortadan kaldırmak isteyebileceğiniz SESSIONve bu nedenle işlem seviyesinin yalnızca bir sonraki işlem için geçerli olmasını sağlayabileceğiniz bir not . Ardından, yukarıdaki üçüncü ifadeyi ile değiştirin COMMIT. Bu, bu durumda bir noop olacaktır, ancak işlemi sonlandırmak ve varsayılan izolasyon seviyesine sıfırlamak gibi bir yan etkiye sahiptir.
Michael Mior

3
Sadece bir not, bu bağlantı
kesildi

5
Üzgünüm, ama burada InnoDB ve MyISAM arasındaki çok önemli farklardan bahsetmediğim için bu yanıta olumsuz oy vermem gerekiyor. Yukarıda @omg tarafından belirtildiği gibi, bu InnoDB için çalışacak ancak MyISAM tabloları için geçerli olmayacaktır.
Simon Forsberg

4
Kesinlikle MyISAM SEÇ sorguları sırasında OKU kilitleri veren olmadığını yanlış @Craig - orada olan bu kilitler tablo istenen tüm YAZIN kilitleri engelleme kilitler, InnoDB için olan kilitler ve karşıt ve yürütme sırasında sonraki tüm sorgular. Orijinal soru InnoDB ile ilgili gibi görünüyor ve izolasyon seviyeleri MyISAM için de mevcut değil - ifade durumu için dokümanlarSET TRANSACTION : "Bu ifade InnoDB tablolarındaki işlemler için kullanılan işlem izolasyon seviyesini belirler."
syneticon-dj

1
Puan kabul edildi. :-) MyISAM ve InnoDB'nin kilitleme davranışına gerçekten atıfta bulunmaya çalışıyordum. Kullandığı yüzden bu yalıtım düzeyi tabanlı çözümler, işlem değildir MyISAM, için geçerli değildir bir basit tablo kilidi. MyISAM UPDATE ve DELETE, tablo kilidinin temizlenmesini beklemek zorundadır, bu nedenle yazma isteğinin arkasındaki sonraki SELECT kuyruğu yazma bitene kadar bloke olur. MyISAM'de "kirli okumalar" yoktur ve çoğu yazma işleminin okumalarla aynı anda gerçekleşmesine izin vermenin bir yolu yoktur, bu nedenle buradaki herhangi bir yorum hakkında "MyISAM'a hitap edememek" için endişelenmenin bir anlamı yoktur. Sanırım ben de buna ulaşıyordum. :-)
Craig

24

Tablo InnoDB ise, bkz. Http://dev.mysql.com/doc/refman/5.1/en/innodb-consistent-read.html - bunu yapan "SEÇİMLER için tutarlı okuma (kilitlemesiz modu) kullanır" innodb_locks_unsafe_for_binlog seçeneği ayarlandıysa ve işlemin izolasyon seviyesi SERIALIZABLE olarak ayarlanmadıysa FOR UPDATE veya LOCK IN SHARE MODE belirtilmez. Bu nedenle, seçilen tablodan okunan satırlarda kilit ayarlanmaz ".


16

kullanım

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED.

Sürüm 5.0 Dokümanlar burada .

Sürüm 5.1 Dokümanlar burada .


2
Teşekkür ederim, sanırım yakın ama bu açıklama ne kadar sürecek? Bu ifadeyi bir PHP programında kullanacağım ve en iyi sorgu bittikten sonra İŞLEM İZOLASYON SEVİYESİNİ otomatik olarak sıfırlamalıyım
omg

14

MySQL kılavuzunun bu sayfasını okumak isteyebilirsiniz . Bir masanın nasıl kilitlendiği, ne tür bir tablo olduğuna bağlıdır.

MyISAM, çok yüksek bir okuma hızı elde etmek için masa kilitleri kullanır, ancak bekleyen bir UPDATE ifadeniz varsa, gelecekteki SELECTS UPDATE'in arkasında sıraya girecektir.

InnoDB masaları satır düzeyinde kilitleme kullanır ve tüm tablonun bir GÜNCELLEME arkasında kilitlenmesine sahip olmazsınız. InnoDB ile ilişkili başka tür kilitleme sorunları da vardır, ancak bunun ihtiyaçlarınıza uygun olduğunu görebilirsiniz.


1
MyISAM tabloları için "İŞLEM İZOLASYON SEVİYESİNİ TAMAMLAMADAN OKUMA AYARLA" çalışacak mı?
omg

5
MyISAM tabloları herhangi bir biçimde işlemleri desteklemez. Bir işlem sorgusu MyISAM tablosunda çalışacaktır, bu nedenle yukarıda bahsettiğiniz sorgu yürütülecektir, ancak hiçbir etkisi yoktur.
zombat

1
O halde SELECTS'in MyISAM durumunda sıraya girmesini önlemek için ne yapabilirim?
omg

6
MyISAM durumunda SELECTS'in sıraya girmesini önlemek için ne yapabilirim? Innodb'ye geç. MyISAM, her sorgu için tablo düzeyinde kilitler kullanır. Bu büyük bir kusur.
Frank Farmer

2

Tablo türünüze bağlı olarak, kilitleme farklı şekilde gerçekleştirilir, ancak bir SELECT sayımı da aynı şekilde gerçekleşir. MyISAM tabloları için basit bir SELECT sayımı (*) FROM tablosu, kayıt sayısını almak için meta verilere eriştiği için tabloyu kilitlememelidir. Innodb, kayıtları saymak için tabloyu anlık görüntüde tutması gerektiğinden daha uzun sürecektir, ancak kilitlenmeye neden olmamalıdır.

En azından concurrent_insert değerini 1 (varsayılan) olarak ayarlamanız gerekir. Daha sonra, tablonun doldurulacağı veri dosyasında "boşluk" yoksa, dosyaya eklemeler eklenecek ve SELECT ve INSERT'ler MyISAM tablolarıyla aynı anda gerçekleşebilir. Bir kaydı silmenin, veri dosyasında gelecekteki eklemeler ve güncellemelerle doldurulmaya çalışacak bir "boşluk" oluşturduğunu unutmayın.

Kayıtları nadiren silerseniz, concurrent_insert değerini 2'ye eşitleyebilirsiniz ve ekler her zaman veri dosyasının sonuna eklenir. Ardından seçimler ve eklemeler aynı anda gerçekleşebilir, ancak kaç kayıt silerseniz silin (tüm kayıtlar hariç) veri dosyanız asla küçülmez.

Sonuç olarak, bir tabloda çok sayıda güncelleme, ekleme ve seçiminiz varsa, bunu InnoDB yapmalısınız. Bir sistemde tablo türlerini özgürce karıştırabilirsiniz.


1

mysql'de kirli okumayı etkinleştirmenin bir başka yolu da ipucu eklemektir: PAYLAŞIM MODUNDA KİLİT

SELECT * FROM TABLE_NAME LOCK IN SHARE MODE; 

"Otomatik yürütme 1 olarak ayarlanırsa, LOCK IN SHARE MODE ve FOR UPDATE yan tümcelerinin hiçbir etkisi olmaz." ... ve autocommit = 1 varsayılandır
Martin Zvarík

0

Gönderen bu referans:

TABLOLARI KİLİTLE ile açık bir şekilde bir tablo kilidi alırsanız, diğer oturumların tabloyu kilitliyken eşzamanlı eklemeler gerçekleştirmesini sağlamak için bir READ kilidi yerine YEREL OKU kilidi talep edebilirsiniz.


0

SELECT'ler normalde InnoDB tablolarında önemsediğiniz herhangi bir kilitleme yapmaz. Varsayılan işlem izolasyon seviyesi, seçimlerin öğeleri kilitlemediği anlamına gelir.

Tabii ki çekişme hala devam ediyor.


1
Bu gönderinin eski olduğunu biliyorum, ancak bu cevap çok genel ve yalnızca bazen doğru. Dev.mysql.com/doc/refman/5.0/en/innodb-locks-set.html adresine bakın . Kilitler kesinlikle edilir yalıtım düzeyine bağlı olarak, okur için satın aldı. Spesifik olarak, bu durumda, poster çoğaltılmış veri tabanlarıyla ilgileniyor show processlistve kilitleri gerçekten görmek için kullanabileceğini açıkça belirtti . Bu nedenle, aslında kilitlerin alındığını varsaymak güvenlidir.
Craig

1
Cevap her zaman doğrudur. Elbette, bazı kilitleme - kullanılan innodb içinde bazı dahili muteksler vardır (örneğin, innodb tampon havuz muteksi). Çoğu kullanıcı bu kilitleri umursamıyor veya fark etmiyor ve normalde yalnızca DDL işlemleri sırasında mücadele ediyorlar (örneğin, 16G tampon havuzunuz varsa ve başka bir iş parçacığında "tabloyu bırak" yaparsanız). Ancak varsayılan olarak herhangi bir sıra kilidi almaz. Demek istediğim şey o. Cevap oldukça belirsizdi.
MarkR

1
Her zaman mı? İşlem yalıtım düzeyi serileştirilebilir olarak ayarlanmışsa veya select deyimi PAYLAŞIM MODUNDA KİLİTLİ kullanıyorsa ve otomatik tamamlama devre dışı bırakılmışsa ne olur? Birçok (çoğu / tümü?) Veritabanı sunucusunun artık gerçek serileştirme yerine varsayılan olarak anlık görüntü yalıtımı kullandığını biliyorum, ancak yine de serileştirilebilir okumaları zorlamak için ara sıra gerekçeler yok mu? Ancak, tüm uzaktan normal durumlarda, MySQL'deki varsayılan koşulların diğer konuları etkileyen okuma kilitlerine neden olmadığını söylüyormuşsunuz gibi geliyor, bu yüzden sahip olmadığınız bir sorun için endişelenmeyin? Olumsuz oyumu geri almaya çalıştım, BTW. Üzgünüm ...
Craig

3
"Normalde yapma" dedim. Demek istediğim, normal bir seçim yaparsanız (PAYLAŞIM MODUNDA GÜNCELLEME veya KİLİTLEME olmadan) ve varsayılan işlem yalıtım düzeyini kullanırsanız. İzolasyon düzeyini değiştirmek için bazı geçerli durumlar vardır, ancak bunu yalnızca oturum başına yapacağım, asla varsayılan değil.
MarkR
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.