MySQL InnoDB veritabanı seçimlerde 'kilitleniyor'


10

Sunucumuzda MySQL yapılandırmasını düzeltmeye çalışıyorum. Uygulamamızın özellikleri çok fazla verinin tek bir tabloda (şu anda 300 milyondan fazla satır) depolanmasıdır. Bu tablo, kesici uçlar için sıklıkla kullanılır (her zaman gelirler).

Bu tabloda birkaç saniyeden uzun süren bir seçme sorgusu çalıştırdığımda, tüm ekler (tam olarak taahhüt eder) tablo erişimi için bekliyor ve uygulamamızı yanıt vermiyor.

Bildiğim kadarıyla InnoDB seçim çalışırken masada herhangi bir kilit yapmak yok. Peki neden seçim engelleme tablosu?

Innotop ile bir neden bulmaya çalıştım ama çıktısını nasıl arayacağımı ve nerede arayacağımı bilmiyorum. Bana neye ihtiyacın olduğunu söyle ve ben buraya göndereceğim.

+-----+---------+-----------+--------+---------+------+----------------+-----------------------------------------------------------------------------------------------------------------------------------+
| Id  | User    | Host      | db     | Command | Time | State          | Info                                                                                                                              |
+-----+---------+-----------+--------+---------+------+----------------+-----------------------------------------------------------------------------------------------------------------------------------+
|   1 | root    | localhost | dbname | Query   |   29 | NULL           | COMMIT                                                                                                                            | 
|   2 | root    | localhost | dbname | Query   |   30 | NULL           | COMMIT                                                                                                                            | 
|   4 | root    | localhost | dbname | Query   |   29 | NULL           | COMMIT                                                                                                                            | 
|   5 | root    | localhost | dbname | Query   |   29 | NULL           | COMMIT                                                                                                                            | 
|   6 | root    | localhost | dbname | Query   |   25 | NULL           | COMMIT                                                                                                                            | 
|   7 | root    | localhost | dbname | Query   |    0 | NULL           | show full processlist                                                                                                             | 
|  13 | user    | localhost | dbname | Query   |   25 | NULL           | COMMIT                                                                                                                            | 
|  38 | user    | localhost | dbname | Sleep   |    0 |                | NULL                                                                                                                              | 
|  39 | user    | localhost | dbname | Sleep   | 9017 |                | NULL                                                                                                                              | 
|  40 | user    | localhost | dbname | Query   |   33 | Sorting result | SELECT * FROM `large_table` WHERE (`large_table`.`hotspot_id` = 3000064)  ORDER BY discovered_at LIMIT 799000, 1000 | 
|  60 | user    | localhost | dbname | Sleep   | 1033 |                | NULL                                                                                                                              | 
|  83 | root    | localhost | dbname | Sleep   | 3728 |                | NULL                                                                                                                              | 
| 112 | root    | localhost | NULL   | Sleep   |    6 |                | NULL                                                                                                                              | 
+-----+---------+-----------+--------+---------+------+----------------+-----------------------------------------------------------------------------------------------------------------------------------+


=====================================
110824 12:24:24 INNODB MONITOR OUTPUT
=====================================
Per second averages calculated from the last 19 seconds
----------
SEMAPHORES
----------
OS WAIT ARRAY INFO: reservation count 1521117, signal count 1471216
Mutex spin waits 0, rounds 20647617, OS waits 239914
RW-shared spins 2119697, OS waits 1037149; RW-excl spins 505734, OS waits 218177
------------
TRANSACTIONS
------------
Trx id counter 0 412917332
Purge done for trx's n:o < 0 412917135 undo n:o < 0 0
History list length 48
Total number of lock structs in row lock hash table 5
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 0 0, not started, process no 28363, OS thread id 1092766032
MySQL thread id 83, query id 3249941 localhost root
---TRANSACTION 0 412901582, not started, process no 28363, OS thread id 1144449360
MySQL thread id 60, query id 3677008 localhost user
---TRANSACTION 0 412917189, not started, process no 28363, OS thread id 1144314192
MySQL thread id 43, query id 3905773 localhost root
---TRANSACTION 0 412534255, not started, process no 28363, OS thread id 1092630864
MySQL thread id 39, query id 14279 localhost user
---TRANSACTION 0 412917331, not started, process no 28363, OS thread id 1144179024
MySQL thread id 38, query id 3908045 localhost user
---TRANSACTION 0 412917201, not started, process no 28363, OS thread id 1092495696
MySQL thread id 13, query id 3908257 localhost user
---TRANSACTION 0 412538821, not started, process no 28363, OS thread id 1092360528
MySQL thread id 7, query id 3908258 localhost root
show engine innodb status
---TRANSACTION 0 412917330, ACTIVE 6 sec, process no 28363, OS thread id 1144043856
2 lock struct(s), heap size 368, undo log entries 1
MySQL thread id 2, query id 3907373 localhost root
COMMIT
Trx read view will not see trx with id >= 0 412917331, sees < 0 412917131
---TRANSACTION 0 412917328, ACTIVE 6 sec, process no 28363, OS thread id 1092225360
2 lock struct(s), heap size 368, undo log entries 1
MySQL thread id 6, query id 3907345 localhost root
COMMIT
Trx read view will not see trx with id >= 0 412917329, sees < 0 412917131
---TRANSACTION 0 412917326, ACTIVE 6 sec, process no 28363, OS thread id 1091955024
2 lock struct(s), heap size 368, undo log entries 1
MySQL thread id 4, query id 3907335 localhost root
COMMIT
Trx read view will not see trx with id >= 0 412917327, sees < 0 412917131
---TRANSACTION 0 412917324, ACTIVE 6 sec, process no 28363, OS thread id 1092090192
2 lock struct(s), heap size 368, undo log entries 1
MySQL thread id 5, query id 3907328 localhost root
COMMIT
Trx read view will not see trx with id >= 0 412917325, sees < 0 412917131
---TRANSACTION 0 412917321, ACTIVE (PREPARED) 7 sec, process no 28363, OS thread id 1143908688 preparing
2 lock struct(s), heap size 368, undo log entries 1
MySQL thread id 1, query id 3907125 localhost root
COMMIT
Trx read view will not see trx with id >= 0 412917322, sees < 0 412917131
---TRANSACTION 0 412917131, ACTIVE 20 sec, process no 28363, OS thread id 1074075984, thread declared inside InnoDB 111
mysql tables in use 1, locked 0
MySQL thread id 40, query id 3904958 localhost user Sorting result
SELECT * FROM `large_table` WHERE (`large_table`.`hotspot_id` = 3000064)  ORDER BY discovered_at LIMIT 848000, 1000
Trx read view will not see trx with id >= 0 412917132, sees < 0 412917132
--------
FILE I/O
--------
I/O thread 0 state: waiting for i/o request (insert buffer thread)
I/O thread 1 state: waiting for i/o request (log thread)
I/O thread 2 state: waiting for i/o request (read thread)
I/O thread 3 state: waiting for i/o request (write thread)
Pending normal aio reads: 0, aio writes: 0,
 ibuf aio reads: 0, log i/o's: 0, sync i/o's: 0
Pending flushes (fsync) log: 1; buffer pool: 0
3510225 OS file reads, 284998 OS file writes, 202897 OS fsyncs
1.05 reads/s, 21299 avg bytes/read, 8.10 writes/s, 7.58 fsyncs/s
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 275, free list len 13392, seg size 13668,
489950 inserts, 491830 merged recs, 10986 merges
Hash table size 8850487, used cells 8127172, node heap has 32697 buffer(s)
71914.53 hash searches/s, 8701.91 non-hash searches/s
---
LOG
---
Log sequence number 157 3331524445
Log flushed up to   157 3331521939
Last checkpoint at  157 3326072846
1 pending log writes, 0 pending chkp writes
199025 log i/o's done, 7.53 log i/o's/second
----------------------
BUFFER POOL AND MEMORY
----------------------
Total memory allocated 4788954432; in additional pool allocated 1048576
Buffer pool size   262144
Free buffers       0
Database pages     229447
Modified db pages  1439
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages read 7453325, created 14887, written 118658
1.37 reads/s, 0.11 creates/s, 0.53 writes/s
Buffer pool hit rate 1000 / 1000
--------------
ROW OPERATIONS
--------------
1 queries inside InnoDB, 0 queries in queue
7 read views open inside InnoDB
Main thread process no. 28363, id 1091684688, state: flushing log
Number of rows inserted 1093064, updated 249134, deleted 1405, read 1115880534
7.89 inserts/s, 2.47 updates/s, 0.05 deletes/s, 80953.21 reads/s
----------------------------
END OF INNODB MONITOR OUTPUT
============================

DÜZENLE:

Bunu açıkladığınız için teşekkürler.

Şimdi sorumu iki davaya bölmeliyim.

  1. Bu tek masada kilitlemenin tüm uygulamamın 'askıda kalmasına' neden olması normal mi? DB diğer tablolara yapılan sorgulara yanıt vermemeli mi? Belki biraz arabellek çok düşük ayarlanmış olabilir?

  2. Bu tabloyu MyISAM olarak değiştirmek yardımcı olacak mı? Bu masada işlem yapmaya hiç ihtiyacım yok. Böyle bir durumda başka kilitler olmayacak mı (uzun seçim + birçok hızlı ekleme)?

EDIT2:

Ekleme sorguları şöyle görünür:

INSERT INTO `large_table` (`device_address`, `hotspot_id`, `minute`, `created_at`, `updated_at`, `discovered_with_hci`, `hour`, `rssi`, `day`, `device_class`, `discovered_at`) VALUES('10:40:03:90:10:40', 3000008, 1, '2011-08-22 05:01:08', '2011-08-22 05:01:08', -1, 5, -79, '2011-08-22 05:01:01', '0', '2011-08-22 05:01:01')

Üzerinde indeksler tanımlanmıştır:

+-------------+------------+----------------------------------------------+--------------+---------------------+-----------+-------------+----------+--------+------+------------+---------+
| Table       | Non_unique | Key_name                                     | Seq_in_index | Column_name         | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+-------------+------------+----------------------------------------------+--------------+---------------------+-----------+-------------+----------+--------+------+------------+---------+
| large_table |          0 | PRIMARY                                      |            1 | id                  | A         |    92396334 |     NULL | NULL   |      | BTREE      |         | 
| large_table |          1 | index_large_table_on_discovered_with_hci     |            1 | discovered_with_hci | A         |          18 |     NULL | NULL   | YES  | BTREE      |         | 
| large_table |          1 | index_large_table_on_hotspot_id              |            1 | hotspot_id          | A         |          18 |     NULL | NULL   | YES  | BTREE      |         | 
| large_table |          1 | index_large_table_on_day_and_hour_and_minute |            1 | day                 | A         |          18 |     NULL | NULL   | YES  | BTREE      |         | 
| large_table |          1 | index_large_table_on_day_and_hour_and_minute |            2 | hour                | A         |          18 |     NULL | NULL   | YES  | BTREE      |         | 
| large_table |          1 | index_large_table_on_day_and_hour_and_minute |            3 | minute              | A         |      537187 |     NULL | NULL   | YES  | BTREE      |         | 
| large_table |          1 | index_large_table_on_created_at              |            1 | created_at          | A         |     8399666 |     NULL | NULL   | YES  | BTREE      |         | 
| large_table |          1 | index_large_table_on_rssi                    |            1 | rssi                | A         |          18 |     NULL | NULL   | YES  | BTREE      |         | 
+-------------+------------+----------------------------------------------+--------------+---------------------+-----------+-------------+----------+--------+------+------------+---------+

DÜZENLEME 3:

Neden bu tür sorgular sırasında başvurum yanıt vermiyor? Sadece bu 'büyük_tabloyu' etkilemez mi?

Belki bir şey benim mysql yapılandırma ile yanlış? Sunucu, 16GB RAM ile 4 çekirdekli Xeon 2GHz'dir. MySQL + Rails Uygulamasını çalıştırır

Yapılandırma parametrelerim:

skip-external-locking
key_buffer              = 64M
max_allowed_packet      = 16M
thread_stack            = 128K
thread_cache_size       = 8
query_cache_size        = 32M
tmp_table_size          = 64M
max_heap_table_size     = 64M
table_cache             = 256
read_rnd_buffer_size    = 512K
sort_buffer_size        = 2M

myisam-recover          = BACKUP
max_connections         = 200

query_cache_limit       = 1M

long_query_time = 200

max_binlog_size         = 100M

innodb_buffer_pool_size = 4G
safe-updates
max_join_size=100000000

Mysqltuner betiği yalnızca şunları önerir:

long_query_time (<= 10)
innodb_buffer_pool_size (>= 62G)

Lütfen çıktısını ekleyin show engine innodb status;.
quanta

Innotop'ta kilitleri görmek için L tuşuna basabilirsiniz. Uygulamanız nasıl bağlantı kurar? JDBC? Hangi defaultTransactionIsolation düzeyini kullanıyorsunuz?
HTTP500

Bu bir RoR uygulamasıdır, bu yüzden MySQL için varsayılan olduğunu tahmin ederim (bir şekilde SQL sorgusu ile kontrol edebilir miyim?). innotop bu seçim çalışırken kilit göstermez.
kaczor1984

@ kaczor1984 Varsayılan yalıtım düzeyini şu işlemleri yaparak kontrol edebilirsiniz: 'tx_isolation' gibi değişkenleri göster; sorgu. Varsayılan REPEATABLE READ'dir. MVCC'nin yalnızca REPEATABLE READ ve READ COMMITTED ile çalıştığını unutmayın. Sorununuzun çözümünün ne olduğundan emin değilim ama RolandoMySQLDBAs yanıtı bilgilendirici oldu.
HTTP500

Yanıtlar:


15

Lütfen işlem listesine ve 'motor innodb durumunu göster'e dikkatlice bakın. Ne görüyorsun ???

İşlem kimlikleri 1,2,4,5,6,13'ün tümü COMMIT'i çalıştırmaya çalışıyor.

Her şeyi kim tutuyor ??? İşlem kimliği 40, büyük_tabloda bir sorgu çalıştırıyor.

Proses ID 40, 33 saniyedir çalışıyor. İşlem kimlikleri 1,2,4,5,6,13, 33 saniyeden az çalışıyor. İşlem Kimliği 40 bir şey işlemektedir. Ne bekliyorsun ???

Her şeyden önce, sorgu large_table en döven olan kümelenmiş endeksi aracılığıyla MVCC .

İşlem Kimlikleri içinde 1,2,4,5,6,13, işlem yalıtımını koruyan MVCC Verileri olan satırlardır. İşlem Kimliği 40, veri satırları arasında yürüyen bir sorguya sahiptir. Hotspot_id alanında bir dizin varsa, bu anahtar + kümelenmiş dizindeki gerçek satırın anahtarı bir iç kilit gerçekleştirmelidir. (Not: Tasarım gereği, InnoDB'deki benzersiz olmayan tüm dizinler hem anahtarınızı (dizine eklemek istediğiniz sütun) + kümelenmiş bir dizin anahtarını taşır). Bu eşsiz senaryo aslında Durdurulamaz Kuvvet, Taşınmaz Nesne ile buluşuyor.

Temel olarak, KOMİTELER, large_table'a değişiklik uygulamak güvenli olana kadar beklemek zorundadır. Durumunuz benzersiz değil, bir kerelik değil, nadir bir fenomen.

Aslında böyle üç soruyu DBA StackExchange'te cevapladım. Aynı kişi ile aynı problemle ilgili sorular iletildi . Cevaplarım çözüm değildi, ancak soru gönderen kişinin durumuyla nasıl başa çıkacağı konusunda kendi sonucuna varmasına yardımcı oldu.

Bu cevaplara ek olarak, başka birinin InnoDB'deki kilitlenmelerle ilgili SELECTs ile ilgili sorusunu yanıtladım .

Umarım bu konudaki geçmiş yayınlarım sana neler olduğunu açıklığa kavuşturmaya yardımcı olur.

GÜNCELLEME 2011-08-25 08:10 EDT

Proses Kimliği 40'tan gelen sorgu

SELECT * FROM `large_table`
WHERE (`large_table`.`hotspot_id` = 3000064)
ORDER BY discovered_at LIMIT 799000, 1000;

İki gözlem:

  • 'SELECT *' yapıyorsunuz Her sütunu almanız mı gerekiyor? Yalnızca belirli sütunlara ihtiyacınız varsa, bunları etiketlemelisiniz çünkü 1000 satırlık geçici tablo gerçekten ihtiyacınız olandan daha büyük olabilir.

  • WHERE ve ORDER BY deyimleri genellikle performans sorunlarını dağıtır veya tablo tasarımının parlak olmasını sağlar. Veri toplamadan önce anahtarların toplanmasını hızlandıracak bir mekanizma oluşturmanız gerekir.

Bu iki gözlem ışığında, yapmanız gereken iki önemli değişiklik vardır:

ÖNEMLİ DEĞİŞİM # 1: Sorguyu yeniden düzenleme

Sorguyu,

  1. anahtarlar dizinden toplanır
  2. sadece 1000 veya
  3. ana masaya geri katıldı

İşte bu üç şeyi yapan yeni sorgu

SELECT large_table.* FROM
large_table INNER JOIN
(
    SELECT hotspot_id,discovered_at
    FROM large_table
    WHERE hotspot_id = 3000064
    ORDER BY discovered_at
    LIMIT 799000,1000
) large_table_keys
USING (hotspot_id,discovered_at);

Large_table_keys alt sorgusu, ihtiyacınız olan 1000 anahtarı toplar. Daha sonra alt sorgudan gelen sonuç INNER büyük_tabakaya birleştirilir. Şimdiye kadar, anahtarlar tüm satırlar yerine alınır. Bu hala okunması gereken 799.000 satır. Bu anahtarları almanın daha iyi bir yolu var, bu da bizi ...

ÖNEMLİ DEĞİŞİM # 2: Yeniden Düzenlenen Sorguyu Destekleyen Dizinler Oluşturma

Yeniden etkinleştirilen sorgu yalnızca bir alt sorgu içerdiğinden, yalnızca bir dizin oluşturmanız gerekir. İşte bu indeks:

ALTER TABLE large_table ADD INDEX hotspot_discovered_ndx (hotspot_id,discovered_at);

Neden bu endeks? WHERE maddesine bakın. Hotspot_id, statik bir değerdir. Bu, tüm hotspot_ids öğelerini dizinde sıralı bir liste oluşturur. Şimdi, ORDER BY yan tümcesine bakın. Discovered_at sütunu muhtemelen bir DATETIME veya TIMESTAMP alanıdır.

Bu endekste sunulan doğal sıra aşağıdaki gibidir:

  • Dizin, bir hostpot_ids listesi içerir
  • Her hotspot_id öğesinin, keşfedilen_at alanlarının sıralı bir listesi var

Bu dizinin yapılması, geçici tabloların dahili olarak sıralanmasını da ortadan kaldırır.

Lütfen bu iki büyük değişikliği yerine koyun ve çalışma süresinde bir fark göreceksiniz.

Bir şans ver !!!

GÜNCELLEME 2011-08-25 08:15 EDT

Endekslerinize baktım. Hala önerdiğim dizini oluşturmanız gerekiyor.


Nasıl çalıştığına dair büyük bir açıklama için teşekkürler. Korkarım böyle durumlardan nasıl kaçınacağımı anlayamıyorum. Ekler dizinleri değiştirmeli ve hotspot_id ve discover__at dizinlerini kullanmalıdır. MyISAM'a geçme fikrime de cevap verebilirseniz sevinirim.
kaczor1984

Aslında, MyISAM'ı kullanmak işleri daha da kötüleştirebilir çünkü MyISAM'deki her INSERT, UPDATE ve DELETE tam bir masa kilidini tetikler. LOW_PRIORITY INSERT veya INSERT DELAYED kullansanız bile, tam tablo kilitleriyle karşılaşılır. Depolama motorundan bağımsız olarak, sorgular bu tür engeller etrafında ayarlanabildiği için sorgunun kendisini keşfetmelisiniz. En azından, tamamen yeni bir algoritma gerekli olabilir. Birkaç dakika içinde sorguya bakacağım ...
RolandoMySQLDBA

İlk yazımı güncelledim, böylece bu tabloda sorguları ve dizinleri ekleyin.
kaczor1984


4
efendim uzun mysql cevaplarınız için erkekler arasında bir kahramansınız
Mike

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.