2011-02-01 32 views
7

Tôi có dịch vụ điểm số cao đơn giản cho trò chơi trực tuyến và nó đã trở nên phổ biến hơn mong đợi. Điểm số cao là một dịch vụ web sử dụng phần phụ trợ MYSQL với một bảng đơn giản như hình dưới đây. Mỗi bản ghi điểm cao được lưu trữ như một hàng trong bảng này. Vấn đề là, với> 140k hàng, tôi thấy một số truy vấn quan trọng nhất làm chậm quá nhiều đến mức nó sẽ sớm quá chậm đối với các yêu cầu dịch vụ.Mở rộng Cơ sở dữ liệu Điểm cao

Bảng chính trông như thế này:

  • id là một chìa khóa duy nhất cho mỗi điểm số kỷ lục
  • trò chơi là số ID của trò chơi mà nộp số điểm (hiện tại, luôn luôn tương đương với "1" , sẽ sớm có để hỗ trợ trò chơi nhiều hơn mặc dù)
  • name là tên hiển thị cho trình của người chơi mà
  • playerid là một ID duy nhất cho một người dùng nào đó
  • điểm là điểm số đại diện cũ 42.035
  • thời gian gửi bài là
  • xếp hạng là một số nguyên lớn duy nhất sắp xếp số lần gửi điểm cho một trò chơi cụ thể. Nó là phổ biến cho mọi người để buộc ở một số điểm nhất định, do đó, trong trường hợp đó tie bị hỏng bởi những người được gửi đầu tiên. Do đó giá trị của lĩnh vực này là tương đương xấp xỉ để "điểm * 100000000 + (MAX_TIME - thời gian)"
 
+----------+---------------+------+-----+---------+----------------+ 
| 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 |    | 
+----------+---------------+------+-----+---------+----------------+ 

Các chỉ số giống như thế này:

 
+-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
| 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  |   | 
+-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 

Khi người dùng yêu cầu điểm cao, họ thường yêu cầu khoảng 75 điểm cao từ một điểm tùy ý trong danh sách "sắp xếp theo xếp hạng giảm dần". Các yêu cầu này thường là "mọi giờ" hoặc chỉ cho điểm số trong 7 ngày qua.

Truy vấn điển hình trông giống như sau: "SELECT * FROM scoretable WHERE game=1 AND time>? ORDER BY rank DESC LIMIT 0, 75;" và chạy trong 0,00 giây.

Tuy nhiên, nếu bạn yêu cầu đến cuối danh sách "SELECT * FROM scoretable WHERE game=1 AND time>? ORDER BY rank DESC LIMIT 10000, 75;" và chạy trong 0,06 giây.

"SELECT * FROM scoretable WHERE game=1 AND time>? ORDER BY rank DESC LIMIT 100000, 75;" và chạy trong 0,58 giây.

Có vẻ như điều này sẽ nhanh chóng bắt đầu nhận quá lâu vì hàng nghìn điểm mới được gửi mỗi ngày!

Ngoài ra, có hai loại truy vấn khác, được sử dụng để tìm một trình phát cụ thể theo id trong danh sách thứ tự được xếp hạng. Họ trông như thế này:

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

theo sau là một

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

câu hỏi

của tôi là: Có thể làm gì để tạo ra một hệ thống mở rộng? Tôi có thể thấy số lượng hàng tăng lên đến vài triệu rất sớm. Tôi đã hy vọng rằng việc lựa chọn một số chỉ số thông minh sẽ giúp ích, nhưng cải tiến này chỉ ở mức thấp.

Cập nhật: Dưới đây là một giải thích dòng:

 
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 | 
+----+-------------+-----------+-------+---------------+------+---------+------+--------+-------------+ 

Solution Tìm thấy!

Tôi đã giải quyết được sự cố nhờ một số gợi ý từ chuỗi này. Làm một chỉ số nhóm là chính xác những gì tôi cần, vì vậy tôi đã chuyển đổi bảng để sử dụng InnoDB trong mysql, hỗ trợ các chỉ số nhóm. Tiếp theo, tôi đã xóa trường id và chỉ đặt khóa chính là (trò chơi ASC, xếp hạng DESC). Bây giờ, tất cả các truy vấn đều chạy siêu nhanh, bất kể tôi sử dụng offset nào. Giải thích cho thấy rằng không có sắp xếp bổ sung nào đang được thực hiện và có vẻ như nó dễ dàng xử lý tất cả lưu lượng truy cập.

+3

Sử dụng Mongo DB. Đó là quy mô web. – anon

+7

Thật kỳ lạ là không thể đánh giá nhận xét ("Sử dụng Mongo DB. Đó là quy mô web.") – zerkms

+1

@ user509841: đưa ra một số giải thích. – zerkms

Trả lời

4

Thấy như thế nào không có người pha, tôi sẽ cho nó một shot. Tôi từ một nền tảng SQL Server, nhưng những ý tưởng tương tự áp dụng.

Một số quan sát chung:

  • Cột ID là khá nhiều vô nghĩa, và không nên tham gia vào bất kỳ chỉ số trừ khi có bảng/truy vấn khác mà bạn không nói cho chúng tôi về. Trong thực tế, nó thậm chí không cần phải có trong truy vấn cuối cùng của bạn. Bạn có thể thực hiện COUNT (*).
  • Chỉ mục nhóm của bạn sẽ nhắm mục tiêu các truy vấn phổ biến nhất của bạn. Do đó, một chỉ số nhóm trên trò chơi ASC, thời gian DESC và xếp hạng DESC hoạt động tốt. Sắp xếp theo thời gian DESC thường là một ý tưởng tốt cho các bảng lịch sử như thế này, nơi bạn thường quan tâm đến những thứ gần đây nhất. Bạn cũng có thể thử một chỉ mục riêng biệt với thứ hạng được sắp xếp theo hướng khác, mặc dù tôi không chắc chắn sẽ có bao nhiêu lợi ích.
  • Bạn có chắc chắn cần SELECT * không? Nếu bạn có thể chọn ít cột hơn, bạn có thể tạo chỉ mục chứa tất cả các cột cần thiết cho SELECT và WHERE của bạn.

1 triệu hàng thực sự không nhiều. Tôi đã tạo một bảng giống như bảng của bạn với 1.000.000 hàng dữ liệu mẫu và thậm chí với một chỉ mục (trò chơi ASC, thời gian DESC và xếp hạng DESC), tất cả các truy vấn chạy trong chưa đầy 1 giây.

(Phần duy nhất tôi không chắc chắn của là playerid. Các truy vấn thực hiện rất tốt mà playerid dường như không cần thiết. Có lẽ bạn có thể thêm nó vào cuối nhóm chỉ số của bạn.)

+0

Cảm ơn! Làm cách nào để tôi tạo chỉ mục nhóm như bạn nói? –

+0

Tôi lấy nó bạn đã tìm ra nó =) Tôi thấy rằng bạn để lại thời gian và playerId ra khỏi chỉ số nhóm của bạn. Họ có thể sẽ hữu ích một ngày, mặc dù bây giờ tôi nghĩ về nó, làm thời gian tăng dần có thể là tốt hơn bởi vì chèn sẽ xảy ra ở phần cuối của các chỉ số. Không chắc chắn về điều này. Hoặc bạn chỉ có thể chuyển sang Mongo DB, vì đó là quy mô web =) – anon

Các vấn đề liên quan