[英]why select different column can affect query speed in mysql 5.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>
上面的表中有4個查詢,它們都使用索引IndexValuateDate,但是查詢1和2非常快(不到1秒),但是查詢3和4非常慢(超過1000秒)。
我注意到1和2僅使用索引來反饋查詢(ID是主鍵,而Valuate_Date已索引)。 3和4首先使用Valuate_Date上的索引過濾表,然后返回表以獲取具有rowid的列? 為什么不僅僅使用像1和2這樣的索引,因為Bond_Key也被索引了?
請提供SHOW CREATE TABLE
。
InnoDB默默地將PRIMARY KEY
的列添加到每個輔助鍵。 因此,查詢1和2執行相同。 他們只使用索引。 這在EXPLAIN
通過Using index
。 也就是說, INDEX(Valuate_Date)
包含所需的列,而其他列則不需要。
EXPLAINs
指示使用了相同的索引,但是沒有“覆蓋”(沒有提到Using index
)。 因此,指數呈線性掃描,但對於每一個估計的98156項與日期,它不得不尋找(在數據的B樹)的價值Bond_Key
。 這種額外的查找導致嚴重的速度下降。 (這1000秒與在HDD上執行98156磁盤命中匹配得很好。)
為了快速進行所有4個查詢, IndexValuateDate
用此復合索引替換IndexValuateDate
,並按給定的順序排列列:
INDEX(Valuate_Date, Bond_Key, ID)
我可以建議您通過DATE
數據類型而不是DECIMAL(8,0)
。
與其他數據庫不同,MySQL沒有“ rowid”。 而是在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
查詢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)。 那正確嗎?
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.