2010-08-16 39 views
5

Tôi đang thực hiện cập nhật trên bảng MySQL (động cơ myisam), theo hồ sơ, chi tiêu một lượng thời gian không đủ trong trạng thái 'init':Truy vấn MySQL: Thời gian dài ở trạng thái 'init'

mysql> show profile for query 2; 
+----------------------+-----------+ 
| Status    | Duration | 
+----------------------+-----------+ 
| starting    | 0.000057 | 
| checking permissions | 0.000006 | 
| Opening tables  | 0.000020 | 
| System lock   | 0.000007 | 
| Table lock   | 0.000005 | 
| init     | 21.911657 | 
| Updating    | 0.002363 | 
| end     | 0.000009 | 
| query end   | 0.000004 | 
| freeing items  | 0.000051 | 
| logging slow query | 0.000003 | 
| logging slow query | 0.000002 | 
| cleaning up   | 0.000005 | 
+----------------------+-----------+ 

các truy vấn như sau:

mysql> update my_table 
    -> set rank = 
    -> greatest(
    ->  @rank := if(@score = score, @rank, @rank + 1), 
    ->  least(0, @score := score) 
    -> ) 
    -> where game=7 and zone=11 and ladder=2 
    -> order by score 
    -> limit 100; 

Query OK, 100 rows affected (21.92 sec) 
Rows matched: 100 Changed: 100 Warnings: 0 

tôi có một số hợp chất trên tất cả các cột được liệt kê trong 'nơi' và 'tự do' khoản (xem chỉ số có tên là 'zone_lad_score' bên dưới):

mysql> show indexes from my_table; 
+--------------------+------------+-----------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+ 
| Table    | Non_unique | Key_name  | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | 
+--------------------+------------+-----------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+ 
| my_table   |   1 | indx_e   |   1 | col_e  | A   |  2937401 |  NULL | NULL |  | BTREE  |   | 
| my_table   |   1 | zone_score  |   1 | zone   | A   |   217 |  NULL | NULL |  | BTREE  |   | 
| my_table   |   1 | zone_score  |   2 | score  | A   | 23499213 |  NULL | NULL | YES | BTREE  |   | 
| my_table   |   1 | zone_d_score |   1 | zone   | A   |   217 |  NULL | NULL |  | BTREE  |   | 
| my_table   |   1 | zone_d_score |   2 | col_d  | A   |  123355 |  NULL | NULL | YES | BTREE  |   | 
| my_table   |   1 | zone_d_score |   3 | score  | A   | 46998427 |  NULL | NULL | YES | BTREE  |   | 
| my_table   |   1 | zone_lad_score |   1 | zone   | A   |   217 |  NULL | NULL |  | BTREE  |   | 
| my_table   |   1 | zone_lad_score |   2 | ladder  | A   |   868 |  NULL | NULL | YES | BTREE  |   | 
| my_table   |   1 | zone_lad_score |   3 | score  | A   | 23499213 |  NULL | NULL | YES | BTREE  |   | 
+--------------------+------------+-----------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+ 

Tôi cũng có bảng được phân vùng trên 'trò chơi', với tổng số 10 phân vùng. Có khoảng 47 triệu tổng số bản ghi trong bảng. định nghĩa bảng như sau: "flushing bản ghi nhị phân, nhật ký InnoDB, và một số hoạt động bộ nhớ cache truy vấn dọn dẹp"

my_table | CREATE TABLE `my_table` (
    `col_e` bigint(20) NOT NULL, 
    `zone` bigint(20) NOT NULL, 
    `score` int(11) DEFAULT NULL, 
    `game` tinyint(4) DEFAULT NULL, 
    `ladder` tinyint(4) DEFAULT NULL, 
    `col_d` int(11) DEFAULT NULL, 
    `rank` int(11) DEFAULT NULL, 
    KEY `indx_e` (`col_e`), 
    KEY `zone_score` (`zone`,`score`), 
    KEY `zone_d_score` (`zone`,`col_d`,`score`), 
    KEY `zone_lad_score` (`zone`,`ladder`,`score`) 
) ENGINE=MyISAM DEFAULT CHARSET=latin1 
/*!50100 PARTITION BY LIST (game) 
(PARTITION p1 VALUES IN (1) ENGINE = MyISAM, 
PARTITION p2 VALUES IN (2) ENGINE = MyISAM, 
PARTITION p3 VALUES IN (3) ENGINE = MyISAM, 
PARTITION p4 VALUES IN (4) ENGINE = MyISAM, 
PARTITION p5 VALUES IN (5) ENGINE = MyISAM, 
PARTITION p6 VALUES IN (6) ENGINE = MyISAM, 
PARTITION p7 VALUES IN (7) ENGINE = MyISAM, 
PARTITION p8 VALUES IN (8) ENGINE = MyISAM, 
PARTITION p9 VALUES IN (9) ENGINE = MyISAM, 
PARTITION p10 VALUES IN (10) ENGINE = MyISAM) */ 

Bây giờ, theo các tài liệu MySQL (http://dev.mysql.com/doc/refman/5.0/en/general-thread-states.html), hành động trong 'init' nhà nước bao gồm Được rồi ... vì tôi không sử dụng InnoDB, có vẻ như không có nhiều thời gian.

Tôi đoán tôi tự hỏi tại sao bản cập nhật này, nên sử dụng chỉ mục và chỉ ảnh hưởng đến 100 bản ghi sẽ mất quá nhiều thời gian? Điều gì đặc biệt sẽ giữ nó trong trạng thái 'init' quá lâu? Nếu tôi thực hiện lựa chọn trên các bản ghi mục tiêu (chọn * từ my_table trong đó game = 7 và zone = 11 và ladder = 2 theo giới hạn điểm 100), nó sẽ trả về gần như ngay lập tức. Thực hiện các cập nhật tương tự trên bảng đó (sử dụng chỉ mục zone_d_score) mất chưa đầy một giây. Điều gì có thể làm chậm cập nhật cụ thể này?

Chỉnh sửa: Đã thêm định nghĩa bảng, liệt kê đầy đủ tất cả các chỉ mục trên bảng được đề cập và đổi tên cột để làm cho mọi thứ dễ theo dõi hơn.

Chỉnh sửa 2: Dưới đây là một 'giải thích' trên truy vấn gần gũi nhất với các bản cập nhật:

mysql> explain select * from my_table where game=7 and zone=11 and ladder=2 order by score limit 100; 
+----+-------------+--------------------+------+------------------------------------------------+-----------------+---------+-------------+-------+-------------+ 
| id | select_type | table    | type | possible_keys         | key    | key_len | ref   | rows | Extra  | 
+----+-------------+--------------------+------+------------------------------------------------+-----------------+---------+-------------+-------+-------------+ 
| 1 | SIMPLE  | my_table   | ref | zone_score,zone_d_score,zone_lad_score   | zone_lad_score | 10  | const,const | 53952 | Using where | 
+----+-------------+--------------------+------+------------------------------------------------+-----------------+---------+-------------+-------+-------------+ 
1 row in set (0.00 sec) 
+0

Cố gắng tạo chỉ mục hợp chất trên col_a, col_b, col_c. Thông thường mysql chỉ có thể sử dụng 1 chỉ mục cho mỗi bảng trong một truy vấn, vì vậy bạn sẽ không nhận được đầy đủ lợi ích từ việc có 3 chỉ mục riêng biệt. – nos

+0

Chỉ mục được hiển thị ở trên * là * chỉ mục phức hợp, theo cột 'seq_in_index' trên lệnh 'chỉ mục hiển thị'. Nó được tạo ra thông qua: tạo chỉ mục my_index trên my_table (col_b, col_c, score); – odonnellt

+0

Bạn có thể gửi một GIẢI THÍCH cho câu lệnh SELECT tương ứng để xem các chỉ mục nào đang thực sự được sử dụng bởi mệnh đề where/order không? – Konerak

Trả lời

1

Sau một số thử nghiệm hơn, tôi đã thêm một chỉ số trên bàn mà còn bao gồm các cột mà tôi chia bảng:

CREATE INDEX game_zone_ladder_score ON my_table(game,zone,ladder,score) 

và đột nhiên UPDATE hoạt động tốt hơn nhiều (phụ thứ hai). Tôi đã mong đợi CẬP NHẬT để tận dụng lợi thế của phân vùng giống như các CHỌN làm, nhưng dường như không.

Vẫn muốn biết chính xác MySQL đang làm gì trong trạng thái 'init' trong suốt CẬP NHẬT, và/hoặc tại sao UPDATE không tôn trọng phân vùng.

0

Có yêu cầu rằng nếu bạn sử dụng phân vùng, cột phân đoạn phải xuất hiện trong khóa chính của bạn. (Điểm Bullet gần phía dưới)

http://dev.mysql.com/tech-resources/articles/mysql_5.1_partitions.html

+0

Đúng, nhưng chỉ khi bảng của bạn thực sự có khóa chính hoặc khóa duy nhất. Nếu không, như trường hợp với bảng của tôi, bạn có thể phân vùng trên một cột khác. – odonnellt

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