2011-02-01 27 views
7

Çevrimiçi bir oyun için basit bir yüksek puan servisim var ve beklenenden daha popüler hale geldi. Yüksek puan, aşağıda gösterildiği gibi basit bir tablo ile MYSQL arka ucunu kullanan bir web servisidir. Her yüksek skor kaydı bu tabloda bir satır olarak saklanır. Sorun şu ki,> 140k satırı ile, bazı anahtar sorguları o kadar yavaşladığını görüyorum ki yakında hizmet istekleri çok yavaş olacak.Yüksek Puan Veri Tabanı Ölçeklendiriliyor

ana tablo aşağıdaki gibidir:

  • id zaman eşit her biri için benzersiz bir anahtar skor oyun şu anda skoru (gönderilen oyunun kimlik numarasıdır
  • rekor olduğu "1" yakında
  • adı o oyuncunun teslim
  • playerid için görünen addır) gerçi daha fazla oyun desteklemek zorunda kalacak
  • skor sayısal puanı gösterimi ex 42035 olan belirli bir kullanıcı için benzersiz bir kimliktir
  • gönderme zamanı
  • sırası, belirli bir oyun için puan gönderimlerini benzersiz şekilde ayıran büyük bir tamsayıdır. İnsanların belirli bir skorla bağlanması için ortak olan , bu nedenle ilk önce kimin gönderdiği ile bağlantı kesilir.

     
    +-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
    | Table  | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | 
    +-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
    | pozscores |   0 | PRIMARY |   1 | id   | A   |  138296 |  NULL | NULL |  | BTREE  |   | 
    | pozscores |   0 | game  |   1 | game  | A   |  NULL |  NULL | NULL | YES | BTREE  |   | 
    | pozscores |   0 | game  |   2 | rank  | A   |  NULL |  NULL | NULL | YES | BTREE  |   | 
    | pozscores |   1 | rank  |   1 | rank  | A   |  138296 |  NULL | NULL | YES | BTREE  |   | 
    +-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
    

    Bir kullanıcı istekleri yüksek puanlar, bunlar genellikle: - "(zaman MAX_TIME) puanı * 100.000.000 +"

    endeksler

 
+----------+---------------+------+-----+---------+----------------+ 
| Field | Type   | Null | Key | Default | Extra   | 
+----------+---------------+------+-----+---------+----------------+ 
| id  | int(11)  | NO | PRI | NULL | auto_increment | 
| game  | int(11)  | YES | MUL | NULL |    | 
| name  | varchar(100) | YES |  | NULL |    | 
| playerId | varchar(50) | YES |  | NULL |    | 
| score | int(11)  | YES |  | NULL |    | 
| time  | datetime  | YES |  | NULL |    | 
| rank  | decimal(50,0) | YES | MUL | NULL |    | 
+----------+---------------+------+-----+---------+----------------+ 
şuna benzer Dolayısıyla bu alanın değeri kabaca eşittir "Sıralı azalan listeye göre sıralı" bir noktadan yaklaşık 75 yüksek puan istemek. Bu talepler genellikle "alltime" veya sadece son 7 gün içindeki puanlar içindir.

Tipik bir sorgu şu şekildedir: "SELECT * FROM scoretable WHERE game=1 AND time>? ORDER BY rank DESC LIMIT 0, 75;" ve 0.00 sn. Ancak, "SELECT * FROM scoretable WHERE game=1 AND time>? ORDER BY rank DESC LIMIT 10000, 75;" listesinin sonuna doğru istekte bulunursanız ve 0,06 saniyede çalışırsa,

"SELECT * FROM scoretable WHERE game=1 AND time>? ORDER BY rank DESC LIMIT 100000, 75;" ve 0,58 saniyede çalışır.

Her gün birkaç bin yeni puanın gönderildiği gibi bu işlem çok hızlı bir şekilde başlayacak gibi görünüyor! Ayrıca, sıralı sıralama listesinde belirli bir oyuncuyu bulmak için iki farklı sorgu türü vardır. Onlar şuna benzer:

"SELECT * FROM scoretable WHERE game=1 AND time>? AND playerId=? ORDER BY rank DESC LIMIT 1"

bir

"SELECT count(id) as count FROM scoretable WHERE game=1 AND time>? AND rank>[rank returned from above]"

Benim soru takip eder: Bu ölçeklenebilir sistem yapmak ne yapılabilir? Çok yakında birkaç milyon olacak şekilde artan satır sayısını görebiliyorum. Bazı akıllı indeksleri seçmenin yardımcı olacağını umuyordum, ancak bu gelişme sadece marjinaldi.

Güncelleme:

 
mysql> explain SELECT * FROM scoretable WHERE game=1 AND time>0 ORDER BY rank DESC LIMIT 100000, 75; 
+----+-------------+-----------+-------+---------------+------+---------+------+--------+-------------+ 
| id | select_type | table  | type | possible_keys | key | key_len | ref | rows | Extra  | 
+----+-------------+-----------+-------+---------------+------+---------+------+--------+-------------+ 
| 1 | SIMPLE  | scoretable| range | game   | game | 5  | NULL | 138478 | Using where | 
+----+-------------+-----------+-------+---------------+------+---------+------+--------+-------------+ 

Çözüm Bulundu: İşte bir çizgi açıklamak olduğunu!

Bu iş parçacığındaki bazı işaretçiler sayesinde sorunu çözdüm. Kümelenmiş bir dizin yapmak tam olarak ihtiyacım olan şeydi, bu yüzden tabloyu kümelenmiş dizinleri destekleyen mysql içinde InnoDB kullanacak şekilde dönüştürdüm. Ardından, id alanını kaldırdım ve sadece birincil anahtarı (oyun ASC, sıralı DESC) ayarlayın. Şimdi, hangi sorguları kullanırsam kullanırım, tüm sorgular çok hızlı çalışır. Açıklama, ek bir sıralama yapılmadığını ve tüm trafiği kolayca işleyebildiğini gösteriyor.

+3

Kullanımı Mongo DB. Bu web ölçeğidir. – anon

+7

Yorumlar reddetmek mümkün değildir ("Mongo DB kullanın. Bu web ölçeği.") – zerkms

+1

@ user509841: bazı açıklar vermek. – zerkms

cevap

4

Katılımcılar olmadıkça, ona bir şans vereceğim. SQL Server arka planındayım, ancak aynı fikirler geçerlidir.

bazı genel gözlemler:

  • kimliği sütunu hemen hemen anlamsız olduğunu ve bize söylemediğin diğer tablolar/sorgular olmadığı sürece herhangi endeksler katılmak olmamalıdır. Aslında, son sorguda olmanıza bile gerek yok. COUNT (*) yapabilirsiniz.
  • Kümelenmiş dizininiz en sık sorulan sorgularınızı hedeflemelidir. Bu nedenle, oyun ASC, zaman DESC ve rank DESC üzerinde kümelenmiş bir dizin iyi çalışır. Zamana göre sıralama DESC, genellikle en yeni şeylerle ilgilendiğiniz yer gibi tarihi tablolar için genellikle iyi bir fikirdir. Sıralamanın diğer yönüne göre sıralandığı ayrı bir indeks de deneyebilirsiniz, ancak bunun ne kadar faydalı olacağından emin değilim.
  • SELECT * 'e ihtiyacınız olduğuna emin misiniz? Daha az sütun seçerseniz, SELECT ve WHERE'niz için gereken tüm sütunları içeren bir dizin oluşturabilirsiniz.

1 milyon satır gerçekten bu kadar değil. 1.000.000 satırlık örnek verisi ile sizinki gibi bir tablo yarattım ve bir endeksle (oyun ASC, zaman DESC ve sıralı DESC) bile, tüm sorgular 1 saniyeden daha kısa bir sürede çalıştı.

(I playerid olduğunu emin değilim sadece bir parçası. Sorguları kadar iyi playerid gerekli değildi o gerçekleştirdi. Belki de kümelenmiş dizinin sonunda ekleyebilirsiniz.)

+0

Teşekkürler! Kümelenmiş endeksi nasıl söylediğiniz gibi oluşturabilirim? –

+0

Bunu çözdüğünüzü anladım =) Kümelenmiş dizininizden zaman ve oyuncu bıraktığınızı görüyorum. Onlar muhtemelen bir gün işe yarayacaklar, ancak şimdi düşünüyorum, artan zaman yapmak daha iyi olabilir çünkü endekslerin sonunda ekler oluşacaktır. Bunun hakkında emin değilim. Veya Mongo DB'ye geçebilirsiniz, çünkü web ölçeği =) – anon