简体   繁体   English

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

[英]why select different column can affect query speed in mysql 5.6?

I have a table cdc_bond_valuation in mysql5.6: 我在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> 

there are 4 querys on the table as above, they all use index IndexValuateDate, but query 1 and 2 are very fast(less than 1 second), but query 3 and 4 very slow(more than 1000 seconds). 上面的表中有4个查询,它们都使用索引IndexValuateDate,但是查询1和2非常快(不到1秒),但是查询3和4非常慢(超过1000秒)。

I notice that 1 and 2 just using index to feedback query(ID is primary key and Valuate_Date is indexed) . 我注意到1和2仅使用索引来反馈查询(ID是主键,而Valuate_Date已索引)。 3 and 4 firstly use index on Valuate_Date to filter table and then back to table get column with rowid ? 3和4首先使用Valuate_Date上的索引过滤表,然后返回表以获取具有rowid的列? why not just use index like 1 and 2 , since Bond_Key also indexed? 为什么不仅仅使用像1和2这样的索引,因为Bond_Key也被索引了?

Please provide SHOW CREATE TABLE . 请提供SHOW CREATE TABLE

InnoDB silently adds the column(s) of the PRIMARY KEY to each secondary key. InnoDB默默地将PRIMARY KEY的列添加到每个辅助键。 Hence queries 1 and 2 perform identically. 因此,查询1和2执行相同。 They use just the index. 他们只使用索引。 This is indicated in EXPLAIN by Using index . 这在EXPLAIN通过Using index That is, INDEX(Valuate_Date) contains the needed columns, and the other columns are not needed. 也就是说, INDEX(Valuate_Date)包含所需的列,而其他列则不需要。

The EXPLAINs indicate that the same index was used, but it was not "covering" (no mention of Using index ). EXPLAINs指示使用了相同的索引,但是没有“覆盖”(没有提到Using index )。 So the index was scanned linearly, but for each of the estimated 98156 entries with that date, it had to look up (in the data's BTree) the value of Bond_Key . 因此,指数呈线性扫描,但对于每一个估计的98156项与日期,它不得不寻找(在数据的B树)的价值Bond_Key This extra lookup caused the severe slowdown. 这种额外的查找导致严重的速度下降。 (The 1000 seconds matches quite well with doing 98156 disk hits on an HDD.) (这1000秒与在HDD上执行98156磁盘命中匹配得很好。)

To make all 4 queries fast, replace IndexValuateDate with this composite index, and put the columns in the order given: 为了快速进行所有4个查询, IndexValuateDate用此复合索引替换IndexValuateDate ,并按给定的顺序排列列:

INDEX(Valuate_Date, Bond_Key, ID)

May I suggest that you work with dates via the DATE datatype, not DECIMAL(8,0) . 我可以建议您通过DATE数据类型而不是DECIMAL(8,0)

Unlike other databases, MySQL has no "rowid". 与其他数据库不同,MySQL没有“ rowid”。 Instead the PRIMARY KEY is used in the BTree for ordering the data. 而是在BTree中使用PRIMARY KEY对数据进行排序。

    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

Query 5: 查询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> 

Query 5 uses index(bond_key) to filter, and then scan the result (787 rows) like full table scann for the bond_key . 查询5使用index(bond_key)进行过滤,然后像全表scann一样扫描结果(787行)以查找bond_key。 Query 5 doesn't use index(ValuateDate) at all. 查询5根本不使用index(ValuateDate)。 Is that right? 那正确吗?

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> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM