We experiencing a slow select on InnoDB comparing to MyISAM - difference for execution on MyISAM is about 2 min., on InnoDB is 2 h.
The number of rows involved is 33 M. The row set in result is about 23M.
Server:
Location: Google Cloud
Disk: 4T SSD
Memory:
[root@gcpjobrunner01 ~]# free -g
total used free shared buff/cache available
Mem: 58 44 0 0 12 13
Swap: 0 0 0
MySQL exact version:
mysql> show global variables like '%version%';
+-------------------------+----------------------------------------------------+
| Variable_name | Value |
+-------------------------+----------------------------------------------------+
| innodb_version | 5.7.24-27 |
| protocol_version | 10 |
| slave_type_conversions | |
| tls_version | TLSv1,TLSv1.1,TLSv1.2 |
| version | 5.7.24-27-log |
| version_comment | Percona Server (GPL), Release 27, Revision bd42700 |
| version_compile_machine | x86_64 |
| version_compile_os | Linux |
| version_suffix | -log |
+-------------------------+----------------------------------------------------+
The DDL of the relevant table:
CREATE TABLE `account_balances` (
`abl_aad_id` double NOT NULL,
`abl_txn_type_cd` varchar(8) NOT NULL,
`abl_prm_code` varchar(30) NOT NULL,
`abl_bal_sort` double NOT NULL DEFAULT '1',
`abl_bal_abl` double NOT NULL,
`abl_bal` double NOT NULL,
`abl_bal_pd` double NOT NULL,
`abl_bal_waived` double NOT NULL,
`abl_bal_chgoff` double NOT NULL DEFAULT '0',
`abl_bal_recovered` double NOT NULL DEFAULT '0',
`abl_bal_adjusted_plus` double NOT NULL DEFAULT '0',
`abl_bal_adjusted_minus` double NOT NULL DEFAULT '0',
`abl_bal_open_ctd` double NOT NULL DEFAULT '0',
`abl_bal_ctd` double NOT NULL,
`abl_bal_pd_ctd` double NOT NULL,
`abl_bal_waived_ctd` double NOT NULL,
`abl_bal_chgoff_open_ctd` double NOT NULL,
`abl_bal_chgoff_ctd` double NOT NULL,
`abl_bal_recovered_ctd` double NOT NULL,
`abl_bal_adjusted_plus_ctd` double NOT NULL,
`abl_bal_adjusted_minus_ctd` double NOT NULL,
`abl_bal_open_ytd` double NOT NULL,
`abl_bal_ytd` double NOT NULL,
`abl_bal_pd_ytd` double NOT NULL,
`abl_bal_waived_ytd` double NOT NULL,
`abl_bal_chgoff_open_ytd` double NOT NULL,
`abl_bal_chgoff_ytd` double NOT NULL,
`abl_bal_recovered_ytd` double NOT NULL,
`abl_bal_adjusted_plus_ytd` double NOT NULL,
`abl_bal_adjusted_minus_ytd` double NOT NULL,
`abl_bal_billed_ind` varchar(30) NOT NULL,
`abl_interest_accrued_ind` varchar(30) NOT NULL DEFAULT 'y',
`abl_chargeoff_method_cd` varchar(30) NOT NULL,
`abl_reschedule_method_cd` varchar(30) NOT NULL,
`abl_writeoff_method_cd` varchar(30) NOT NULL,
`abl_bal_open_ctd1` double NOT NULL DEFAULT '0',
`abl_bal_ctd1` double NOT NULL,
`abl_bal_pd_ctd1` double NOT NULL,
`abl_bal_waived_ctd1` double NOT NULL,
`abl_bal_chgoff_open_ctd1` double NOT NULL,
`abl_bal_chgoff_ctd1` double NOT NULL,
`abl_bal_recovered_ctd1` double NOT NULL,
`abl_bal_adjusted_plus_ctd1` double NOT NULL,
`abl_bal_adjusted_minus_ctd1` double NOT NULL,
`abl_bal_open_ytd1` double NOT NULL,
`abl_bal_ytd1` double NOT NULL,
`abl_bal_pd_ytd1` double NOT NULL,
`abl_bal_waived_ytd1` double NOT NULL,
`abl_bal_chgoff_open_ytd1` double NOT NULL,
`abl_bal_chgoff_ytd1` double NOT NULL DEFAULT '0',
`abl_bal_recovered_ytd1` double NOT NULL DEFAULT '0',
`abl_bal_adjusted_plus_ytd1` double NOT NULL DEFAULT '0',
`abl_bal_adjusted_minus_ytd1` double NOT NULL DEFAULT '0',
`abl_bill_method_cd` varchar(30) NOT NULL DEFAULT 'lv',
`abl_pmt_amt` double NOT NULL,
`abl_pmt_per` double NOT NULL DEFAULT '0',
`abl_dt` datetime NOT NULL,
`abl_prom_type_cd` varchar(30) NOT NULL,
`abl_rate` double NOT NULL,
`abl_term` double NOT NULL,
`abl_prm_end_dt` datetime NOT NULL,
`abl_due_amt1` double NOT NULL,
`abl_due_amt2` double NOT NULL,
`abl_due_amt3` double NOT NULL,
`abl_due_amt4` double NOT NULL DEFAULT '0',
`abl_due_amt5` double NOT NULL,
`abl_due_amt_pd1` double NOT NULL,
`abl_due_amt_pd2` double NOT NULL,
`abl_due_amt_pd3` double NOT NULL,
`abl_due_amt_pd4` double NOT NULL,
`abl_due_amt_pd5` double NOT NULL,
`abl_pin_code` varchar(30) NOT NULL DEFAULT 'undefined',
`abl_ins_sub_type_cd` varchar(30) NOT NULL DEFAULT 'undefined',
`abl_ins_status_cd` varchar(30) NOT NULL,
`abl_acc_orig_sys_xref` varchar(30) NOT NULL,
`created_by` varchar(30) NOT NULL,
`creation_date` datetime NOT NULL,
`last_updated_by` varchar(30) NOT NULL,
`last_update_date` datetime NOT NULL,
`abl_bal_terminate` double NOT NULL,
`abl_bal_terminate_ctd` double NOT NULL,
`abl_bal_terminate_ytd` double NOT NULL,
`abl_bal_terminate_ctd1` double NOT NULL,
`abl_bal_terminate_ytd1` double NOT NULL,
`abl_terminate_ind` varchar(30) NOT NULL,
`abl_bal_abl_ctd1` double NOT NULL,
`abl_bal_abl_ctd2` double NOT NULL,
`abl_bal_abl_ctd3` double NOT NULL,
`abl_bal_abl_ctd4` double NOT NULL DEFAULT '0',
`abl_bal_abl_ctd5` double NOT NULL DEFAULT '0',
`abl_non_perform_roll_ind` varchar(30) NOT NULL,
`abl_non_perform_txn_type_cd` varchar(30) NOT NULL,
`abl_bal_xfer2non_perform` double NOT NULL,
`abl_bal_pd_xfer2non_perform` double NOT NULL,
`abl_non_perform_bal` double NOT NULL,
`abl_non_perform_bal_pd` double NOT NULL,
`abl_non_perform_bal_pd_excess` double NOT NULL,
`abl_non_perform_bal_waived` double NOT NULL,
`abl_non_perform_bal_adj_plus` double NOT NULL,
`abl_non_perform_bal_adj_minus` double NOT NULL,
`abl_bal_billed` double NOT NULL,
`abl_bal_billed_ctd` double NOT NULL,
`abl_bal_billed_ctd1` double NOT NULL,
`abl_bal_billed_ytd` double NOT NULL,
UNIQUE KEY `account_balances_abl_udx` (`abl_aad_id`,`abl_txn_type_cd`,`abl_prm_code`),
KEY `abl_txn_type_cd` (`abl_txn_type_cd`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
The DDL is the same for the query run on MyISAM.
Here is the query:
SELECT
abl_aad_id,
abl_txn_type_cd,
abl_bal_chgoff,
abl_bal_recovered,
abl_bal,
abl_bal_pd,
abl_bal_waived,
abl_bal_adjusted_minus,
abl_bal_adjusted_plus
FROM
account_balances
WHERE abl_txn_type_cd IN ('ADV','INT','FLC','FNSF','FEXT','FOTH1','FPHP','EBKR','ERPO','ESVC','EOTH1','ADV');
Here is the actual SQL from SP:
SELECT NOW(), 'Creating tmp_mv_account_balances';
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SET sql_mode=(SELECT REPLACE(@@sql_mode, 'ONLY_FULL_GROUP_BY', ''));
DROP TABLE IF EXISTS tmp_mv_account_balances;
CREATE TABLE tmp_mv_account_balances AS
SELECT acc_nbr AS "acc_nbr_bal",
abl_aad_id AS "aad_id_bal",
ROUND(SUM( CASE WHEN abl_txn_type_cd = 'ADV' THEN CASE WHEN acc_status_cd = 'CHGOFF' THEN abl_bal_chgoff - abl_bal_recovered ELSE abl_bal - abl_bal_pd - abl_bal_waived - abl_bal_adjusted_minus + abl_bal_adjusted_plus END ELSE 0 END ) , 2) AS "advance_principal_bal",
ROUND(SUM( CASE WHEN abl_txn_type_cd = 'INT' THEN CASE WHEN acc_status_cd = 'CHGOFF' THEN abl_bal_chgoff - abl_bal_recovered ELSE abl_bal - abl_bal_pd - abl_bal_waived - abl_bal_adjusted_minus + abl_bal_adjusted_plus END ELSE 0 END ) , 2) AS "interest_bal",
ROUND(SUM( CASE WHEN abl_txn_type_cd = 'FLC' THEN CASE WHEN acc_status_cd = 'CHGOFF' THEN abl_bal_chgoff - abl_bal_recovered ELSE abl_bal - abl_bal_pd - abl_bal_waived - abl_bal_adjusted_minus + abl_bal_adjusted_plus END ELSE 0 END ) , 2) AS "fee_late_charge_bal",
ROUND(SUM( CASE WHEN abl_txn_type_cd = 'FNSF' THEN CASE WHEN acc_status_cd = 'CHGOFF' THEN abl_bal_chgoff - abl_bal_recovered ELSE abl_bal - abl_bal_pd - abl_bal_waived - abl_bal_adjusted_minus + abl_bal_adjusted_plus END ELSE 0 END ) , 2) AS "fee_nsf_bal",
ROUND(SUM( CASE WHEN abl_txn_type_cd = 'FEXT' THEN CASE WHEN acc_status_cd = 'CHGOFF' THEN abl_bal_chgoff - abl_bal_recovered ELSE abl_bal - abl_bal_pd - abl_bal_waived - abl_bal_adjusted_minus + abl_bal_adjusted_plus END ELSE 0 END ) , 2) AS "fee_extension_bal",
ROUND(SUM( CASE WHEN abl_txn_type_cd = 'FOTH1' THEN CASE WHEN acc_status_cd = 'CHGOFF' THEN abl_bal_chgoff - abl_bal_recovered ELSE abl_bal - abl_bal_pd - abl_bal_waived - abl_bal_adjusted_minus + abl_bal_adjusted_plus END ELSE 0 END ) , 2) AS "fee_convenience_bal",
ROUND(SUM( CASE WHEN abl_txn_type_cd = 'FPHP' THEN CASE WHEN acc_status_cd = 'CHGOFF' THEN abl_bal_chgoff - abl_bal_recovered ELSE abl_bal - abl_bal_pd - abl_bal_waived - abl_bal_adjusted_minus + abl_bal_adjusted_plus END ELSE 0 END ) , 2) AS "fee_phone_pay_bal",
ROUND(SUM( CASE WHEN abl_txn_type_cd = 'EBKR' THEN CASE WHEN acc_status_cd = 'CHGOFF' THEN abl_bal_chgoff - abl_bal_recovered ELSE abl_bal - abl_bal_pd - abl_bal_waived - abl_bal_adjusted_minus + abl_bal_adjusted_plus END ELSE 0 END ) , 2) AS "expense_legal_bal",
ROUND(SUM( CASE WHEN abl_txn_type_cd = 'ERPO' THEN CASE WHEN acc_status_cd = 'CHGOFF' THEN abl_bal_chgoff - abl_bal_recovered ELSE abl_bal - abl_bal_pd - abl_bal_waived - abl_bal_adjusted_minus + abl_bal_adjusted_plus END ELSE 0 END ) , 2) AS "expense_repo_bal",
ROUND(SUM( CASE WHEN abl_txn_type_cd = 'ESVC' THEN CASE WHEN acc_status_cd = 'CHGOFF' THEN abl_bal_chgoff - abl_bal_recovered ELSE abl_bal - abl_bal_pd - abl_bal_waived - abl_bal_adjusted_minus + abl_bal_adjusted_plus END ELSE 0 END ) , 2) AS "expense_dmv_bal",
ROUND(SUM( CASE WHEN abl_txn_type_cd = 'EOTH1' THEN CASE WHEN acc_status_cd = 'CHGOFF' THEN abl_bal_chgoff - abl_bal_recovered ELSE abl_bal - abl_bal_pd - abl_bal_waived - abl_bal_adjusted_minus + abl_bal_adjusted_plus END ELSE 0 END ) , 2) AS "expense_deferred_bal",
ROUND(SUM( CASE WHEN abl_txn_type_cd = 'ADV' THEN CASE WHEN acc_status_cd = 'CHGOFF' THEN abl_bal_chgoff - abl_bal_recovered ELSE abl_bal - abl_bal_pd - abl_bal_waived - abl_bal_adjusted_minus + abl_bal_adjusted_plus - acc_int_rebate_amt END ELSE 0 END ) , 2) AS "net_advance_principal_bal",
acc_int_rebate_amt AS "int_rebate_bal"
FROM
account_balances
JOIN accounts ON abl_aad_id = acc_aad_id
GROUP BY
abl_aad_id;
SELECT NOW(), 'Creating indexes';
ALTER TABLE tmp_mv_account_balances ADD INDEX idx01_bal ( acc_nbr_bal );
ALTER TABLE tmp_mv_account_balances ADD INDEX idx02_bal ( aad_id_bal );
MyISAM is returning the result in 2 min., but in InnoDB it is taking "forever".
Explain plan for InnoDB:
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
------ ----------- ---------------- ---------- ------ --------------- ------ ------- ------ -------- -------- -------------
1 SIMPLE account_balances (NULL) ALL abl_txn_type_cd (NULL) (NULL) (NULL) 28858313 100.00 Using where
Explain plan in MyISAM:
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
------ ----------- ---------------- ---------- ------ ------------- ------ ------- ------ -------- -------- -------------
1 SIMPLE account_balances (NULL) ALL (NULL) (NULL) (NULL) (NULL) 33628821 50.00 Using where
Here is explain plan with force index (abl_txn_type_cd)
for InnoDB, we dont have that index in MyISAM, but it does not matter - the SELECT is running forever in InnoDB.
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
------ ----------- ---------------- ---------- ------ --------------- --------------- ------- ------ -------- -------- -----------------------
1 SIMPLE account_balances (NULL) range abl_txn_type_cd abl_txn_type_cd 10 (NULL) 40672694 100.00 Using index condition
Here is SHOW TABLE STATUS InnoDB:
mysql> show table status like 'account_balances';
+------------------+--------+---------+------------+----------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+-------------------+----------+-----------------------+---------+
| Name | Engine | Version | Row_format | Rows | Avg_row_length | Data_length | Max_data_length | Index_length | Data_free | Auto_increment | Create_time | Update_time | Check_time | Collation | Checksum | Create_options | Comment |
+------------------+--------+---------+------------+----------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+-------------------+----------+-----------------------+---------+
| account_balances | InnoDB | 10 | Compressed | 31858884 | 521 | 16606822400 | 0 | 1128251392 | 4194304 | NULL | 2019-02-09 15:35:01 | NULL | NULL | latin1_swedish_ci | NULL | row_format=COMPRESSED | |
+------------------+--------+---------+------------+----------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+-------------------+----------+-----------------------+---------+
1 row in set (0.00 sec)
Here is the InnoDB buffers info:
mysql> show global variables like '%innodb_buffer%';
+-------------------------------------+----------------+
| Variable_name | Value |
+-------------------------------------+----------------+
| innodb_buffer_pool_chunk_size | 134217728 |
| innodb_buffer_pool_dump_at_shutdown | ON |
| innodb_buffer_pool_dump_now | OFF |
| innodb_buffer_pool_dump_pct | 25 |
| innodb_buffer_pool_filename | ib_buffer_pool |
| innodb_buffer_pool_instances | 8 |
| innodb_buffer_pool_load_abort | OFF |
| innodb_buffer_pool_load_at_startup | ON |
| innodb_buffer_pool_load_now | OFF |
| innodb_buffer_pool_size | 42949672960 |
+-------------------------------------+----------------+
10 rows in set (0.00 sec)
Can someone provide some advice?
key_buffer_size
andinnodb_buffer_pool_size
. Note: they compete for RAM, and should be adjusted based on which Engine is dominant.