MySQL查詢的優化是個老生常談的問題,方法更是多種多樣,其中最直接的就是建立索引.html
這裏經過一個簡單的demo來實際用一下索引,看看索引在百萬級別查詢中速率的提高效果如何mysql
所需數據能夠從我前面的一篇博客中獲取:http://www.javashuo.com/article/p-muuqjoke-bh.htmlsql
有一張salaries,app
查看錶結構以下: 測試
mysql> desc salaries; +-----------+---------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-----------+---------+------+-----+---------+-------+ | emp_no | int(11) | NO | PRI | NULL | | | salary | int(11) | NO | | NULL | | | from_date | date | NO | PRI | NULL | | | to_date | date | NO | | NULL | | +-----------+---------+------+-----+---------+-------+
能夠看到emp_no,from_date都是PRI(主鍵索引),這是在這個表中將這兩個字段聯合起來設置爲主鍵,一張表中仍是隻能有一個主鍵優化
查看錶的建立命令:spa
mysql> show create table salaries; +----------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +----------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | salaries | CREATE TABLE `salaries` ( `emp_no` int(11) NOT NULL, `salary` int(11) NOT NULL, `from_date` date NOT NULL, `to_date` date NOT NULL, PRIMARY KEY (`emp_no`,`from_date`), CONSTRAINT `salaries_ibfk_1` FOREIGN KEY (`emp_no`) REFERENCES `employees` (`emp_no`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=latin1 | +----------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec)
注意我標紅的地方,將emp_no`,`from_date設置爲組合主鍵,組合索引聽從左前綴原則,查詢emp_no,或者查詢(`emp_no`,`from_date`)會走索引,可是查from_date不會走索引,能夠看一下用explain命令查看:code
mysql> explain select * from salaries where emp_no=227694; +----+-------------+----------+------+---------------+---------+---------+-------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+----------+------+---------------+---------+---------+-------+------+-------+ | 1 | SIMPLE | salaries | ref | PRIMARY | PRIMARY | 4 | const | 18 | NULL | # key爲PRIMARY 走了索引 +----+-------------+----------+------+---------------+---------+---------+-------+------+-------+ 1 row in set (0.01 sec) mysql> explain select * from salaries where from_date = '1986-06-26'; +----+-------------+----------+------+---------------+------+---------+------+---------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+----------+------+---------------+------+---------+------+---------+-------------+ | 1 | SIMPLE | salaries | ALL | NULL | NULL | NULL | NULL | 2838426 | Using where | key爲Null,Extra 使用了where,沒走索引 +----+-------------+----------+------+---------------+------+---------+------+---------+-------------+ 1 row in set (0.00 sec) mysql> explain select * from salaries where from_date = '1986-06-26' and emp_no=75047; +----+-------------+----------+-------+---------------+---------+---------+-------------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+----------+-------+---------------+---------+---------+-------------+------+-------+ | 1 | SIMPLE | salaries | const | PRIMARY | PRIMARY | 7 | const,const | 1 | NULL | # key爲PRIMARY 走了索引
+----+-------------+----------+-------+---------------+---------+---------+-------------+------+-------+
1 row in set (0.00 sec)
to_date字段沒有設置索引,咱們來測試一下加索引先後,該字段查詢效率會不會有提高:htm
未加索引:blog
mysql> select * from salaries where to_date = '1986-06-26'; +--------+--------+------------+------------+ | emp_no | salary | from_date | to_date | +--------+--------+------------+------------+ | 25676 | 40000 | 1985-06-26 | 1986-06-26 | | 28757 | 40000 | 1985-06-26 | 1986-06-26 | | 30860 | 64620 | 1985-06-26 | 1986-06-26 | | 69209 | 40000 | 1985-06-26 | 1986-06-26 | | 80550 | 45292 | 1985-06-26 | 1986-06-26 | | 91204 | 47553 | 1985-06-26 | 1986-06-26 | | 96140 | 52908 | 1985-06-26 | 1986-06-26 | | 208352 | 42989 | 1985-06-26 | 1986-06-26 | | 213109 | 90133 | 1985-06-26 | 1986-06-26 | | 217498 | 80247 | 1985-06-26 | 1986-06-26 | | 219462 | 83880 | 1985-06-26 | 1986-06-26 | | 223150 | 40000 | 1985-06-26 | 1986-06-26 | | 227694 | 73897 | 1985-06-26 | 1986-06-26 | | 232856 | 73126 | 1985-06-26 | 1986-06-26 | | 237619 | 56982 | 1985-06-26 | 1986-06-26 | | 244087 | 40000 | 1985-06-26 | 1986-06-26 | | 253472 | 72004 | 1985-06-26 | 1986-06-26 | | 257395 | 40000 | 1985-06-26 | 1986-06-26 | | 261811 | 40000 | 1985-06-26 | 1986-06-26 | | 268968 | 40000 | 1985-06-26 | 1986-06-26 | | 269331 | 40000 | 1985-06-26 | 1986-06-26 | | 274805 | 40000 | 1985-06-26 | 1986-06-26 | | 279432 | 74530 | 1985-06-26 | 1986-06-26 | | 285685 | 83198 | 1985-06-26 | 1986-06-26 | | 286745 | 44082 | 1985-06-26 | 1986-06-26 | | 290901 | 49876 | 1985-06-26 | 1986-06-26 | | 400719 | 79168 | 1985-06-26 | 1986-06-26 | | 401448 | 49600 | 1985-06-26 | 1986-06-26 | | 427374 | 40000 | 1985-06-26 | 1986-06-26 | | 432024 | 40000 | 1985-06-26 | 1986-06-26 | | 432654 | 40000 | 1985-06-26 | 1986-06-26 | | 438461 | 44451 | 1985-06-26 | 1986-06-26 | | 446228 | 42733 | 1985-06-26 | 1986-06-26 | | 447391 | 62381 | 1985-06-26 | 1986-06-26 | | 448823 | 40000 | 1985-06-26 | 1986-06-26 | | 452355 | 40000 | 1985-06-26 | 1986-06-26 | | 453590 | 61615 | 1985-06-26 | 1986-06-26 | | 456521 | 40000 | 1985-06-26 | 1986-06-26 | | 464415 | 48955 | 1985-06-26 | 1986-06-26 | | 467901 | 52349 | 1985-06-26 | 1986-06-26 | | 472895 | 40000 | 1985-06-26 | 1986-06-26 | | 476501 | 40000 | 1985-06-26 | 1986-06-26 | | 477079 | 40000 | 1985-06-26 | 1986-06-26 | | 478934 | 55054 | 1985-06-26 | 1986-06-26 | | 480301 | 44177 | 1985-06-26 | 1986-06-26 | | 484507 | 40000 | 1985-06-26 | 1986-06-26 | | 486187 | 40000 | 1985-06-26 | 1986-06-26 | | 491159 | 46034 | 1985-06-26 | 1986-06-26 | | 493154 | 40000 | 1985-06-26 | 1986-06-26 | | 498140 | 81909 | 1985-06-26 | 1986-06-26 | | 498565 | 72853 | 1985-06-26 | 1986-06-26 | +--------+--------+------------+------------+ 51 rows in set (1.08 sec)
用explain分析一下:
mysql> explain select * from salaries where to_date = '1986-06-26'; +----+-------------+----------+------+---------------+------+---------+------+---------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+----------+------+---------------+------+---------+------+---------+-------------+ | 1 | SIMPLE | salaries | ALL | NULL | NULL | NULL | NULL | 2838426 | Using where | # Extra使用where。key爲Null,在2838426條數據中找51條記錄用時1.08s +----+-------------+----------+------+---------------+------+---------+------+---------+-------------+ 1 row in set (0.00 sec)
爲to_date字段加索引:
mysql> create index to_date on salaries(to_date); Query OK, 0 rows affected (5.31 sec) Records: 0 Duplicates: 0 Warnings: 0 建立索引會耗時,索然提高了查詢速率,可是更新添加動做會效率下降
如今看一下表結構:
mysql> desc salaries; +-----------+---------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-----------+---------+------+-----+---------+-------+ | emp_no | int(11) | NO | PRI | NULL | | | salary | int(11) | NO | | NULL | | | from_date | date | NO | PRI | NULL | | | to_date | date | NO | MUL | NULL | | MUL表示非惟一索引 +-----------+---------+------+-----+---------+-------+ 4 rows in set (0.00 sec) mysql> show create table salaries; +----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | salaries | CREATE TABLE `salaries` ( `emp_no` int(11) NOT NULL, `salary` int(11) NOT NULL, `from_date` date NOT NULL, `to_date` date NOT NULL, PRIMARY KEY (`emp_no`,`from_date`), KEY `to_date` (`to_date`), # 建立了索引key爲to_date CONSTRAINT `salaries_ibfk_1` FOREIGN KEY (`emp_no`) REFERENCES `employees` (`emp_no`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=latin1 | +----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec)
再次查詢:
mysql> select * from salaries where to_date = '1986-06-26'; +--------+--------+------------+------------+ | emp_no | salary | from_date | to_date | +--------+--------+------------+------------+ | 25676 | 40000 | 1985-06-26 | 1986-06-26 | | 28757 | 40000 | 1985-06-26 | 1986-06-26 | | 30860 | 64620 | 1985-06-26 | 1986-06-26 | | 69209 | 40000 | 1985-06-26 | 1986-06-26 | | 80550 | 45292 | 1985-06-26 | 1986-06-26 | | 91204 | 47553 | 1985-06-26 | 1986-06-26 | | 96140 | 52908 | 1985-06-26 | 1986-06-26 | | 208352 | 42989 | 1985-06-26 | 1986-06-26 | | 213109 | 90133 | 1985-06-26 | 1986-06-26 | | 217498 | 80247 | 1985-06-26 | 1986-06-26 | | 219462 | 83880 | 1985-06-26 | 1986-06-26 | | 223150 | 40000 | 1985-06-26 | 1986-06-26 | | 227694 | 73897 | 1985-06-26 | 1986-06-26 | | 232856 | 73126 | 1985-06-26 | 1986-06-26 | | 237619 | 56982 | 1985-06-26 | 1986-06-26 | | 244087 | 40000 | 1985-06-26 | 1986-06-26 | | 253472 | 72004 | 1985-06-26 | 1986-06-26 | | 257395 | 40000 | 1985-06-26 | 1986-06-26 | | 261811 | 40000 | 1985-06-26 | 1986-06-26 | | 268968 | 40000 | 1985-06-26 | 1986-06-26 | | 269331 | 40000 | 1985-06-26 | 1986-06-26 | | 274805 | 40000 | 1985-06-26 | 1986-06-26 | | 279432 | 74530 | 1985-06-26 | 1986-06-26 | | 285685 | 83198 | 1985-06-26 | 1986-06-26 | | 286745 | 44082 | 1985-06-26 | 1986-06-26 | | 290901 | 49876 | 1985-06-26 | 1986-06-26 | | 400719 | 79168 | 1985-06-26 | 1986-06-26 | | 401448 | 49600 | 1985-06-26 | 1986-06-26 | | 427374 | 40000 | 1985-06-26 | 1986-06-26 | | 432024 | 40000 | 1985-06-26 | 1986-06-26 | | 432654 | 40000 | 1985-06-26 | 1986-06-26 | | 438461 | 44451 | 1985-06-26 | 1986-06-26 | | 446228 | 42733 | 1985-06-26 | 1986-06-26 | | 447391 | 62381 | 1985-06-26 | 1986-06-26 | | 448823 | 40000 | 1985-06-26 | 1986-06-26 | | 452355 | 40000 | 1985-06-26 | 1986-06-26 | | 453590 | 61615 | 1985-06-26 | 1986-06-26 | | 456521 | 40000 | 1985-06-26 | 1986-06-26 | | 464415 | 48955 | 1985-06-26 | 1986-06-26 | | 467901 | 52349 | 1985-06-26 | 1986-06-26 | | 472895 | 40000 | 1985-06-26 | 1986-06-26 | | 476501 | 40000 | 1985-06-26 | 1986-06-26 | | 477079 | 40000 | 1985-06-26 | 1986-06-26 | | 478934 | 55054 | 1985-06-26 | 1986-06-26 | | 480301 | 44177 | 1985-06-26 | 1986-06-26 | | 484507 | 40000 | 1985-06-26 | 1986-06-26 | | 486187 | 40000 | 1985-06-26 | 1986-06-26 | | 491159 | 46034 | 1985-06-26 | 1986-06-26 | | 493154 | 40000 | 1985-06-26 | 1986-06-26 | | 498140 | 81909 | 1985-06-26 | 1986-06-26 | | 498565 | 72853 | 1985-06-26 | 1986-06-26 | +--------+--------+------------+------------+ 51 rows in set (0.00 sec) # 建立索引後一樣的查詢條件從1.08s變爲了0.00s,驚訝吧
explain分析:
mysql> explain select * from salaries where to_date = '1986-06-26'; +----+-------------+----------+------+---------------+---------+---------+-------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+----------+------+---------------+---------+---------+-------+------+-------+ | 1 | SIMPLE | salaries | ref | to_date | to_date | 3 | const | 51 | NULL | key從Null變味了索引字段to_date,row從兩百多萬變爲了51 +----+-------------+----------+------+---------------+---------+---------+-------+------+-------+ 1 row in set (0.00 sec)
這個demo從數據上直觀的體現了索引帶來的查詢效率提高有多可觀,可是索引也是有利必有害,更多索引的底層知識能夠參考這位大牛的博客:http://www.javashuo.com/article/p-ocmahjoq-k.html