Почему выбор другого столбца может повлиять на скорость запроса в MySQL 5.6? - PullRequest
0 голосов
/ 07 декабря 2018

У меня есть таблица cdc_bond_valuation в mysql5.6:

+--------------+--------------------+--------------+---------------------------------+--------------+--------------+-------------+
| 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 голосов
/ 10 декабря 2018
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> 
0 голосов
/ 10 декабря 2018
    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
0 голосов
/ 10 декабря 2018

Запрос 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 использует индекс (bond_key) для фильтрации, а затем сканирует результат (787 строк), как полное сканирование таблицы для bond_key.Запрос 5 вообще не использует индекс (ValuateDate).Это верно?

0 голосов
/ 07 декабря 2018

Пожалуйста, укажите SHOW CREATE TABLE.

InnoDB автоматически добавляет столбец (и) PRIMARY KEY к каждому вторичному ключу.Следовательно, запросы 1 и 2 выполняются одинаково.Они используют только индекс.Это указано в EXPLAIN как Using index.Таким образом, INDEX(Valuate_Date) содержит необходимые столбцы, а другие столбцы не нужны.

EXPLAINs указывает, что использовался тот же индекс, но он не был «охватывающим» (без упоминания Using index).Таким образом, индекс сканировался линейно, но для каждой из примерно 98156 записей с этой датой он должен был искать (в BTree данных) значение Bond_Key.Этот дополнительный поиск вызвал серьезное замедление.(1000 секунд очень хорошо подходят для выполнения 98156 обращений к диску на жестком диске.)

Чтобы ускорить все 4 запроса, замените IndexValuateDate на этот составной индекс и расположите столбцы в указанном порядке:

INDEX(Valuate_Date, Bond_Key, ID)

Могу ли я предложить вам работать с датами через тип данных DATE, а не DECIMAL(8,0).

В отличие от других баз данных, MySQL не имеет "rowid".Вместо этого PRIMARY KEY используется в BTree для упорядочивания данных.

...