案例:MySQL優化器如何選擇索引和JOIN順序(2)

發表于:2013-05-06來源:不祥作者:不詳點擊數: 標簽:MySQL
(*) 選擇第一個JOIN的表為A (**) 確定A表的訪問方式 因為A表是第一個表,所以無法使用索引`IND_DID`(B.DepartmentID = A.DepartmentID) 那么只能使用索引`IND_L_D`(A.Last

  (*) 選擇第一個JOIN的表為A

  (**) 確定A表的訪問方式

  因為A表是第一個表,所以無法使用索引`IND_DID`(B.DepartmentID = A.DepartmentID)

  那么只能使用索引`IND_L_D`(A.LastName = 'zhou')

  使用IND_L_D索引的成本計算,總成本為25.2;參考前面計算;

  (**) 這里訪問A表的成本已經是25.2,比之前的最優成本2.4要大,忽略該順序

  所以,這次窮舉搜索到此結束

  把上面的過程簡化如下:

  (*) 選擇第一個JOIN的表為B

  (**) 確定B表的訪問方式

  (**) 從剩余的表中窮舉選出第二個JOIN的表,這里剩余的表為:A

  (**) 將A表加入JOIN,并確定其訪問方式

  (***) IND_L_D A.LastName = 'zhou'

  (***) IND_DID B.DepartmentID = A.DepartmentID

  (***) IND_L_D成本為25.2;IND_DID成本為1.2,所以選擇后者為當前表的訪問方式

  (**) 確定A使用索引IND_DID,訪問方式為ref

  (**) JOIN順序B|A,總成本為:1.2+1.2 = 2.4

  (*) 選擇第一個JOIN的表為A

  (**) 確定A表的訪問方式

  (**) 這里訪問A表的成本已經是25.2,比之前的最優成本2.4要大,忽略該順序

  至此,MySQL優化器就確定了所有表的最佳JOIN順序和訪問方式。

  3. 測試環境

  MySQL: 5.1.48-debug-log innodb plugin 1.0.9

  CREATE TABLE `department` (

  `DepartmentID` int(11) DEFAULT NULL,

  `DepartmentName` varchar(20) DEFAULT NULL,

  KEY `IND_D` (`DepartmentID`),

  KEY `IND_DN` (`DepartmentName`)

  ) ENGINE=InnoDB DEFAULT CHARSET=gbk;

  CREATE TABLE `employee` (

  `LastName` varchar(20) DEFAULT NULL,

  `DepartmentID` int(11) DEFAULT NULL,

  KEY `IND_L_D` (`LastName`),

  KEY `IND_DID` (`DepartmentID`)

  ) ENGINE=InnoDB DEFAULT CHARSET=gbk;

  for i in `seq 1 1000` ; do mysql -vvv -uroot test -e 'insert into department values (600000*rand(),repeat(char(65+rand()*58),rand()*20))'; done

  for i in `seq 1 1000` ; do mysql -vvv -uroot test -e 'insert into employee values (repeat(char(65+rand()*58),rand()*20),600000*rand())'; done

  for i in `seq 1 50` ; do mysql -vvv -uroot test -e 'insert into employee values ("zhou",27760)'; done

  for i in `seq 1 200` ; do mysql -vvv -uroot test -e 'insert into employee values (repeat(char(65+rand()*58),rand()*20),27760)'; done

  for i in `seq 1 1` ; do mysql -vvv -uroot test -e 'insert into department values (27760,"TBX")'; done

  show index from employee;

  +----------+------------+----------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+

  | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |

  +----------+------------+----------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+

  | employee | 1 | IND_L_D | 1 | LastName | A | 1349 | NULL | NULL | YES | BTREE | |

  | employee | 1 | IND_DID | 1 | DepartmentID | A | 1349 | NULL | NULL | YES | BTREE | |

  +----------+------------+----------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+

  show index from department;

  +------------+------------+----------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+

  | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |

  +------------+------------+----------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+

  | department | 1 | IND_D | 1 | DepartmentID | A | 1001 | NULL | NULL | YES | BTREE | |

  | department | 1 | IND_DN | 1 | DepartmentName | A | 1001 | NULL | NULL | YES | BTREE | |

  +------------+------------+----------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+

  4. 構造一個Bad case

  因為關聯條件中MySQL使用索引統計信息做成本預估,所以數據分布不均勻的時候,就容易做出錯誤的判斷。簡單的我們構造下面的案例:

  表和索引結構不變,按照下面的方式構造數據:

  for i in `seq 1 10000` ; do mysql -uroot test -e 'insert into department values (600000*rand(),repeat(char(65+rand()*58),rand()*20))'; done

  for i in `seq 1 10000` ; do mysql -uroot test -e 'insert into employee values (repeat(char(65+rand()*58),rand()*20),600000*rand())'; done

  for i in `seq 1 1` ; do mysql -uroot test -e 'insert into employee values ("zhou",27760)'; done

  for i in `seq 1 10` ; do mysql -uroot test -e 'insert into department values (27760,"TBX")'; done

原文轉自:http://www.orczhou.com/index.php/2013/04/how-mysql-choose-index-in-a-join/

国产97人人超碰caoprom_尤物国产在线一区手机播放_精品国产一区二区三_色天使久久综合给合久久97