220 milyon satırlık tablodaki sorguları nasıl hızlandırabilirim (9 gig veri)?


31

Sorun:

Üyelerin uyumluluk veya eşleşme için birbirlerini değerlendirebilecekleri bir sosyal sitemiz var. Bu user_match_ratingstablo 220 milyondan fazla satır içeriyor (9 gig veri veya indekslerde yaklaşık 20 gig). Bu tabloya karşı sorgular rutin olarak slow.log'da gösterilir (eşik> 2 saniye) ve sistemde en sık kaydedilen yavaş sorgudur:

Query_time: 3  Lock_time: 0  Rows_sent: 3  Rows_examined: 1051
"select rating, count(*) as tally from user_match_ratings where rated_user_id = 395357 group by rating;"

Query_time: 4  Lock_time: 0  Rows_sent: 3  Rows_examined: 1294
"select rating, count(*) as tally from user_match_ratings where rated_user_id = 4182969 group by rating;"

Query_time: 3  Lock_time: 0  Rows_sent: 3  Rows_examined: 446
"select rating, count(*) as tally from user_match_ratings where rated_user_id = 630148 group by rating;"

Query_time: 5  Lock_time: 0  Rows_sent: 3  Rows_examined: 3788
"select rating, count(*) as tally from user_match_ratings where rated_user_id = 1835698 group by rating;"

Query_time: 17  Lock_time: 0  Rows_sent: 3  Rows_examined: 4311
"select rating, count(*) as tally from user_match_ratings where rated_user_id = 1269322 group by rating;"

MySQL sürümü:

  • protokol sürümü: 10
  • sürüm: 5.0.77-log
  • bdb sürümü: Sleepycat Yazılımı: Berkeley DB 4.1.24: (29 Ocak 2009)
  • sürüm derleme makinesi: x86_64 version_compile_os: redhat-linux-gnu

Tablo bilgisi:

SHOW COLUMNS FROM user_match_ratings;

verir:

╔═══════════════╦════════════╦════╦═════╦════════╦════════════════╗
 id             int(11)     NO  PRI  NULL    auto_increment 
 rater_user_id  int(11)     NO  MUL  NULL                   
 rated_user_id  int(11)     NO  MUL  NULL                   
 rating         varchar(1)  NO       NULL                   
 created_at     datetime    NO       NULL                   
╚═══════════════╩════════════╩════╩═════╩════════╩════════════════╝

Örnek sorgu:

select * from mutual_match_ratings where id=221673540;

verir:

╔═══════════╦═══════════════╦═══════════════╦════════╦══════════════════════╗
 id         rater_user_id  rated_user_id  rating  created_at           
╠═══════════╬═══════════════╬═══════════════╬════════╬══════════════════════╣
 221673540  5699713        3890950        N       2013-04-09 13:00:38  
╚═══════════╩═══════════════╩═══════════════╩════════╩══════════════════════╝

endeksleri

Tabloda 3 indeks ayarlandı:

  1. tek dizin açık rated_user_id
  2. bileşik dizin rater_user_idvecreated_at
  3. bileşik dizin rated_user_idverater_user_id
user_match_ratings dizinini göster;

verir:

╔════════════════════╦════════════╦═══════════════════════════╦══════════════╦═══════════════╦═══════════╦═════════════╦══════════╦════════╦═════════════════════════╦════════════╦══════════════════╗
 Table               Non_unique  Key_name                   Seq_in_index  Column_name    Collation  Cardinality  Sub_part  Packed  Null                     Index_type  Comment          
╠════════════════════╬════════════╬═══════════════════════════╬══════════════╬═══════════════╬═══════════╬═════════════╬══════════╬════════╬═════════════════════════╬════════════╬══════════════════╣
 user_match_ratings  0           PRIMARY                    1             id             A          220781193    NULL      NULL    BTREE                                                 
 user_match_ratings  1           user_match_ratings_index1  1             rater_user_id  A          11039059     NULL      NULL    BTREE                                                 
 user_match_ratings  1           user_match_ratings_index1  2             created_at     A          220781193    NULL      NULL    BTREE                                                 
 user_match_ratings  1           user_match_ratings_index2  1             rated_user_id  A          4014203      NULL      NULL    BTREE                                                 
 user_match_ratings  1           user_match_ratings_index2  2             rater_user_id  A          220781193    NULL      NULL    BTREE                                                 
 user_match_ratings  1           user_match_ratings_index3  1             rated_user_id  A          2480687      NULL      NULL    BTREE                                                 
╚════════════════════╩════════════╩═══════════════════════════╩══════════════╩═══════════════╩═══════════╩═════════════╩══════════╩════════╩═════════════════════════╩════════════╩══════════════════╝

Dizinlerde bile bu sorgular yavaş.

Benim sorum:

Bu tabloyu / verileri, bu verileri bellekte depolamak için yeterince ram olan bir sunucudaki başka bir veritabanına ayırmak, bu sorguları hızlandırabilir mi? Yine de, bu sorguları daha hızlı yapmak için geliştirebileceğimiz tabloların / indekslerin ayarlandığı herhangi bir şey var mı?

Şu anda 16GB belleğimiz var; ancak mevcut makineyi 32GB'a yükseltmeyi ya da en azından bu kadar katı hal sürücüleriyle yeni bir makine eklemeyi düşünüyoruz.


1
Sorunuz inanılmaz. Şu anki çözümünüzle, <= 2 saniye içinde sonuç almayı nasıl başardığınızı merak ediyorum. Çünkü sadece 20 milyon kayıttan oluşan bir masam var ve hala 30 saniye sürüyor SELECT QUERY. Lütfen önerir misiniz? PS Sorunuz beni bu topluluğa katılmaya zorladı (y);)
NullPointer

2
Sorguladığınız tablodaki dizinlere bakın. Genellikle uygun dizin oluşturularak sorgularda birçok iyileştirme yapılabilir. Her zaman değil ama sorguların nerede yapıldığına dair çok sayıda örnek görüldü, sorgudaki where cümlesindeki sütunlara karşı bir dizin sağlayarak. Özellikle bir masa büyüyüp büyürse.
Ranknoodle

@ Ranknoodle'ın emin olun. Teşekkür ederim. Sırasıyla kontrol edeceğim.
NullPointer

Yanıtlar:


28

Konuyla ilgili düşünceler rastgele sırada atılır:

  • Bu sorgu için bariz endeksidir: (rated_user_id, rating). Milyonlarca kullanıcıdan yalnızca biri için veri alan ve 17 saniyeye ihtiyaç duyan bir sorgu yanlış bir şey yapıyor: Dizinden okumak (rated_user_id, rater_user_id)ve sonra tablodan okumak ( herhangi bir dizinde olmadığı ratinggibi ) sütun için (yüzlerce) değerleri rating. Bu nedenle, sorgunun birçok farklı disk konumunda bulunan tablonun birçok satırını okuması gerekir.

  • Tablolara çok sayıda dizin eklemeye başlamadan önce, tüm veritabanının performansını, tüm yavaş sorgu kümesini analiz etmeye çalışın, veri tiplerinin, kullandığınız motorun ve konfigürasyon ayarlarının seçimini tekrar inceleyin.

  • MySQL'in daha yeni bir sürümüne geçmeyi düşünün, 5.1, 5.5 veya hatta 5.6 (ayrıca: Percona ve MariaDB sürümleri.) Hatalar giderildikten sonraki bazı avantajlar düzeltildi, optimizer geliştirildi ve yavaş sorgular için düşük eşiği 1 saniyeden az (10 milisaniye gibi). Bu yavaş sorgular hakkında size çok daha iyi bilgi verecektir.

  • Veri türü için seçim ratingtuhaf. VARCHAR(1)? Neden olmasın CHAR(1)? Neden olmasın TINYINT? Bu, hem teneke kutuyu hem de bu sütunu içerecek indekslerde biraz yer kazandıracaktır. Bir varchar (1) sütunu char (1) üzerinden bir bayt daha gerektirir ve eğer utf8 ise, (var) char sütunları 1 (tinyint) yerine 3 (veya 4) bayta ihtiyaç duyar.


2
Yanlış veri türünü kullanırsanız, performans açısından% veya performans kaybı ne kadardır?
FlyingAtom

1
@FlyingAtom Duruma göre değişir, ancak yine de taranması gereken bazı indeksli sütunlar için (örneğin, burada bir cümlecik olmadığında ancak yalnızca bu sütunu alıyorsanız), motor dizini taramaya karar verebilir Tablo ve veri türünüzü boyutun yarısı kadar optimize ederseniz, tarama o zaman iki kat daha hızlı olur ve yanıt yarı boyuttadır. Dizini yerine tabloyu hala tarıyorsanız (örneğin, yalnızca dizindeki sütunları değil, daha fazla sütun aldığınızda), faydalar daha az önemli olacaktır.
Sebastián Grignoli

-1

Alman Hükümeti için bazen 60 milyon kayıtla masa tuttum.

Bu masaların çoğunda vardı.

Ve toplam tablodaki satırları defalarca bilmemiz gerekiyordu.

Oracle ve Microsoft programcıları ile konuştuktan sonra çok mutlu olmadık ...

Bu yüzden, biz, veritabanı programcıları grubu olarak, her tabloda her zaman toplam kayıt numaralarının kaydedildiği kayıt olan bir kayıt olduğuna karar verdik. INSERT veya DELETE satırlarına bağlı olarak bu numarayı güncelledik.

Diğer tüm yolları denedik. Bu çok hızlı bir şekilde.

1998'den beri bu şekilde kullanıyoruz ve tüm multi milyon kayıt tablolarımızda hiçbir zaman yanlış satır olmadı.


7
Son 18 yılda tanıtılan özelliklerden bazılarına göz atmanızı öneririm. Diğerleri arasında count(*), bazı gelişmeler var.
dezso

Onları sayamazsan hiç yanlış numaraya sahip olmadığınızı nereden biliyorsunuz? uhmmmm ...
Tonca

-3

Gibi derecelendirme türlerinde bölümlenmeye çalışacağım:

mutual_match_ratings_N, mutual_match_ratings_S, vb.

Her tür için bir sorgu gerçekleştirmelisiniz, ancak belki de diğer yoldan daha hızlıdır. Bir şans ver.

Bu, sabit sayıda derecelendirme türünüz olduğunu ve bu tabloya bu yeni yapıyla en kötü olabilecek diğer sorgular için ihtiyacınız olmadığını varsayar.

Bu durumda, başka bir yaklaşım aramalı ya da alan ve bakım kolaylığı (veya uygulama mantığı) açısından uygunsa, tablonun iki kopyasını (başlangıç ​​tablonuz ve bölümlenmiş olanlar) tutmalısınız.

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.