我正在執行一個MySQL表(myisam引擎)的更新,根據分析器,它在'初始化'狀態花費過多時間:MySQL查詢:在'初始化'狀態花費的時間太長
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 |
+----------------------+-----------+
查詢如下:
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
我對在「其中」和列出的所有列的複合索引「以便通過」條款(見下文命名爲「zone_lad_score」指數):
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 | |
+--------------------+------------+-----------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+
我也有'遊戲'分區,共有10個分區。表中總共有約4700萬條記錄。表定義如下:
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) */
現在,根據MySQL的文檔(http://dev.mysql.com/doc/refman/5.0/en/general-thread-states.html),在「初始化」狀態的行動包括「刷新二進制日誌,InnoDB的日誌,以及一些查詢緩存清理操作。」好吧...因爲我沒有使用InnoDB,聽起來不像是需要花費很多時間的東西。
我想我想知道爲什麼這個更新應該使用索引,隻影響100個記錄會花費這麼長時間?特別是在'初始'狀態持續這麼久會有什麼特別的呢?如果我在定位記錄上執行選擇(select * from my_table where game = 7 and zone = 11 and ladder = 2 order by score limit 100),它幾乎立即返回。在該表上執行類似的更新(使用zone_d_score索引)不到一秒鐘。什麼可能會放慢這個特定的更新?
編輯:增加了表格定義,問題表中所有索引的完整列表,以及重命名的列使事情更容易遵循。
編輯2:這裏有最接近更新查詢的「解釋」:
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)
嘗試創建上爲col_a,col_b,col_c一個複合索引。通常,mysql只能在查詢中爲每個表使用1個索引,所以你不能從3個獨立索引中獲得全部好處。 – nos 2010-08-16 08:14:33
上面顯示的索引*是一個複合索引,按照'show indexes'命令中的'seq_in_index'列。它是通過以下方式創建的:在my_table上創建索引my_index(col_b,col_c,score); – odonnellt 2010-08-16 08:17:05
您能否爲相應的SELECT語句發佈EXPLAIN以查看哪些索引實際上由where/order子句使用? – Konerak 2010-08-16 08:54:05