为什么选择不同的列会影响mysql 5.6中的查询速度?

时间:2018-12-07 03:36:04

标签: mysql performance indexing explain

我在mysql5.6中有一个表cdc_bond_valuation:

+--------------+--------------------+--------------+---------------------------------+--------------+--------------+-------------+
| table_schema | table_name         | index_schema | index_name                      | seq_in_index | column_name  | cardinality |
+--------------+--------------------+--------------+---------------------------------+--------------+--------------+-------------+
| ss_product   | cdc_bond_valuation | ss_product   | IDX_cdc_bond_valuation_Bond_Key |            1 | Bond_Key     |      377844 |
| ss_product   | cdc_bond_valuation | ss_product   | IndexValuateDate                |            1 | Valuate_Date |      143025 |
| ss_product   | cdc_bond_valuation | ss_product   | PRIMARY                         |            1 | ID           |    25315548 |
+--------------+--------------------+--------------+---------------------------------+--------------+--------------+-------------+



query 1:
SELECT  Valuate_Date  FROM cdc_bond_valuation WHERE Valuate_Date = 20181203;

query 2:
SELECT ID, Valuate_Date  FROM cdc_bond_valuation WHERE Valuate_Date = 20181203;

query 3:
SELECT  Bond_Key FROM cdc_bond_valuation WHERE Valuate_Date = 20181203;

query 4:
SELECT  Bond_Key,Valuate_Date FROM cdc_bond_valuation WHERE Valuate_Date = 20181203;


explain 1:
mysql> explain SELECT  Valuate_Date  FROM cdc_bond_valuation WHERE Valuate_Date = 20181203;
+----+-------------+--------------------+------+------------------+------------------+---------+-------+-------+-------------+
| id | select_type | table              | type | possible_keys    | key              | key_len | ref   | rows  | Extra       |
+----+-------------+--------------------+------+------------------+------------------+---------+-------+-------+-------------+
|  1 | SIMPLE      | cdc_bond_valuation | ref  | IndexValuateDate | IndexValuateDate | 5       | const | 98156 | Using index |
+----+-------------+--------------------+------+------------------+------------------+---------+-------+-------+-------------+
1 row in set

explain 2:
mysql> explain SELECT  ID,Valuate_Date FROM cdc_bond_valuation WHERE Valuate_Date = 20181203;
+----+-------------+--------------------+------+------------------+------------------+---------+-------+-------+-------------+
| id | select_type | table              | type | possible_keys    | key              | key_len | ref   | rows  | Extra       |
+----+-------------+--------------------+------+------------------+------------------+---------+-------+-------+-------------+
|  1 | SIMPLE      | cdc_bond_valuation | ref  | IndexValuateDate | IndexValuateDate | 5       | const | 98156 | Using index |
+----+-------------+--------------------+------+------------------+------------------+---------+-------+-------+-------------+
1 row in set


explain 3:
mysql> explain SELECT  Bond_Key FROM cdc_bond_valuation WHERE Valuate_Date = 20181203;
+----+-------------+--------------------+------+------------------+------------------+---------+-------+-------+-------+
| id | select_type | table              | type | possible_keys    | key              | key_len | ref   | rows  | Extra |
+----+-------------+--------------------+------+------------------+------------------+---------+-------+-------+-------+
|  1 | SIMPLE      | cdc_bond_valuation | ref  | IndexValuateDate | IndexValuateDate | 5       | const | 98156 | NULL  |
+----+-------------+--------------------+------+------------------+------------------+---------+-------+-------+-------+
1 row in set

explain 4:
mysql> explain SELECT  Bond_Key,Valuate_Date FROM cdc_bond_valuation WHERE Valuate_Date = 20181203;
+----+-------------+--------------------+------+------------------+------------------+---------+-------+-------+-------+
| id | select_type | table              | type | possible_keys    | key              | key_len | ref   | rows  | Extra |
+----+-------------+--------------------+------+------------------+------------------+---------+-------+-------+-------+
|  1 | SIMPLE      | cdc_bond_valuation | ref  | IndexValuateDate | IndexValuateDate | 5       | const | 98156 | NULL  |
+----+-------------+--------------------+------+------------------+------------------+---------+-------+-------+-------+
1 row in set



mysql> select table_schema,
       table_name,
       index_schema,
       index_name,
       seq_in_index,
       column_name,
       cardinality
  from information_schema.statistics
 where table_name = 'cdc_bond_valuation'
 order by table_schema, table_name, index_name, seq_in_index;

+--------------+--------------------+--------------+---------------------------------+--------------+--------------+-------------+
| table_schema | table_name         | index_schema | index_name                      | seq_in_index | column_name  | cardinality |
+--------------+--------------------+--------------+---------------------------------+--------------+--------------+-------------+
| ss_product   | cdc_bond_valuation | ss_product   | IDX_cdc_bond_valuation_Bond_Key |            1 | Bond_Key     |      377844 |
| ss_product   | cdc_bond_valuation | ss_product   | IndexValuateDate                |            1 | Valuate_Date |      143025 |
| ss_product   | cdc_bond_valuation | ss_product   | PRIMARY                         |            1 | ID           |    25315548 |
+--------------+--------------------+--------------+---------------------------------+--------------+--------------+-------------+
3 rows in set

mysql> 

如上表中有4个查询,它们都使用索引IndexValuateDate,但是查询1和2很快(不到1秒),但是查询3和4却很慢(超过1000秒)。

我注意到1和2仅使用索引来反馈查询(ID是主键,而Valuate_Date已索引)。 3和4首先使用Valuate_Date上的索引过滤表,然后返回表以获取具有rowid的列?为什么不只使用像1和2这样的索引,因为Bond_Key也被索引了?

4 个答案:

答案 0 :(得分:0)

请提供SHOW CREATE TABLE

InnoDB静默地将PRIMARY KEY的列添加到每个辅助键。因此,查询1和2执行相同。他们只使用索引。这在EXPLAIN中用Using index表示。也就是说,INDEX(Valuate_Date)包含所需的列,而其他列则不需要。

EXPLAINs指示使用了相同的索引,但未“覆盖”(未提及Using index)。因此,对索引进行了线性扫描,但是对于该日期的估计98156个条目中的每个条目,它必须(在数据的BTree中)查找Bond_Key的值。这种额外的查找导致严重的速度下降。 (1000秒与在HDD上执行98156磁盘命中匹配得很好。)

要快速进行所有4个查询,请用此复合索引替换IndexValuateDate,并按给定的顺序排列列:

INDEX(Valuate_Date, Bond_Key, ID)

我可以建议您通过DATE数据类型而不是DECIMAL(8,0)处理日期。

与其他数据库不同,MySQL没有“ rowid”。而是在树中使用PRIMARY KEY来对数据进行排序。

答案 1 :(得分:0)

    CREATE TABLE `cdc_bond_valuation` (
  `ID` varchar(32) NOT NULL,
  `Bond_Key` varchar(25) DEFAULT NULL,
  `Short_Name` varchar(32) DEFAULT NULL,
  `Bond_ID` varchar(32) DEFAULT NULL,
  `Valuate_Date` decimal(8,0) DEFAULT NULL,
  `Listed_Market` varchar(3) DEFAULT NULL,
  `Remaining_Year` decimal(7,4) DEFAULT NULL,
  `Val_Intraday_Dirty_Price` decimal(7,4) DEFAULT NULL,
  `Val_Intraday_Accrued_Interest` decimal(7,4) DEFAULT NULL,
  `Val_Clean_Price` decimal(7,4) DEFAULT NULL,
  `Val_Yield` decimal(7,4) DEFAULT NULL,
  `Val_Modified_Duration` decimal(7,4) DEFAULT NULL,
  `Val_Convexity` decimal(7,4) DEFAULT NULL,
  `Val_Basis_Point_Value` decimal(7,4) DEFAULT NULL,
  `Val_Spread_Duration` decimal(7,4) DEFAULT NULL,
  `Val_Spread_Convexity` decimal(7,4) DEFAULT NULL,
  `Market_Dirty_Price` decimal(7,4) DEFAULT NULL,
  `Market_Clean_Price` decimal(7,4) DEFAULT NULL,
  `Market_Yield` decimal(7,4) DEFAULT NULL,
  `Market_Modified_Duration` decimal(7,4) DEFAULT NULL,
  `Market_Convexity` decimal(7,4) DEFAULT NULL,
  `Market_Basis_Point_Value` decimal(7,4) DEFAULT NULL,
  `Market_Spread_Duration` decimal(7,4) DEFAULT NULL,
  `Market_Spread_Convexity` decimal(7,4) DEFAULT NULL,
  `Credibility` varchar(16) DEFAULT NULL,
  `Val_Rate_Duration` decimal(7,4) DEFAULT NULL,
  `Val_Rate_Convexity` decimal(7,4) DEFAULT NULL,
  `Market_Rate_Duration` decimal(7,4) DEFAULT NULL,
  `Market_Rate_Convexity` decimal(7,4) DEFAULT NULL,
  `Val_Closed_Dirty_Price` decimal(7,4) DEFAULT NULL,
  `Val_Closed_Accrued_Interest` decimal(7,4) DEFAULT NULL,
  `Remaining_Par_Value` decimal(7,4) DEFAULT NULL,
  `Val_Spread` decimal(7,4) DEFAULT NULL,
  `Yield_Curve_ID` varchar(128) DEFAULT NULL,
  `Market_Spread` decimal(7,4) DEFAULT NULL,
  `Absolute_Liquidity_Coefficient` decimal(7,4) DEFAULT NULL,
  `Position_Percentage` decimal(7,4) DEFAULT NULL,
  `Relative_Liquidity_Coefficient` decimal(7,4) DEFAULT NULL,
  `Relative_Liquidity_Value` decimal(7,4) DEFAULT NULL,
  `Option` varchar(8) DEFAULT NULL ,
  PRIMARY KEY (`ID`),
  KEY `IndexValuateDate` (`Valuate_Date`) USING BTREE,
  KEY `ValuateDateBondKey` (`Valuate_Date`,`Bond_Key`),
  KEY `IndexBondKey` (`Bond_Key`,`Listed_Market`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8

答案 2 :(得分:0)

查询5:

mysql> explain SELECT Bond_Key, Valuate_Date  FROM cdc_bond_valuation WHERE Valuate_Date = 20181203  and bond_key='C0000832017CORLEB01';
+----+-------------+--------------------+------+--------------------------------------------------+---------------------------------+---------+-------+------+------------------------------------+
| id | select_type | table              | type | possible_keys                                    | key                             | key_len | ref   | rows | Extra                              |
+----+-------------+--------------------+------+--------------------------------------------------+---------------------------------+---------+-------+------+------------------------------------+
|  1 | SIMPLE      | cdc_bond_valuation | ref  | IndexValuateDate,IDX_cdc_bond_valuation_Bond_Key | IDX_cdc_bond_valuation_Bond_Key | 78      | const |  787 | Using index condition; Using where |
+----+-------------+--------------------+------+--------------------------------------------------+---------------------------------+---------+-------+------+------------------------------------+
1 row in set

mysql> 

查询5使用index(bond_key)进行过滤,然后像全表scann一样扫描结果(787行)以查找bond_key。查询5根本不使用index(ValuateDate)。是吗?

答案 3 :(得分:0)

SELECT  count(*)  FROM cdc_bond_valuation WHERE   bond_key='C0000832017CORLEB01';
SELECT  count(*)  FROM cdc_bond_valuation WHERE   bond_key='C0000832017CORLEB01' and Valuate_Date = 20181203;


+----------+
| count(*) |
+----------+
|      788 |
+----------+
1 row in set

+----------+
| count(*) |
+----------+
|        2 |
+----------+
1 row in set

mysql>