查询性能问题 - 对于 select 语句,即使表上有超过 20 万亿条记录的索引

Posted

技术标签:

【中文标题】查询性能问题 - 对于 select 语句,即使表上有超过 20 万亿条记录的索引【英文标题】:Query Performance Issue - for select statement even with indexes on the table with more than 20 Trillion records 【发布时间】:2015-01-05 03:12:03 【问题描述】:

我们有三个表,需要从三个表中选择记录,即 拥有 162161 条记录的账户 Account_Types 6 条记录 有10761247条记录的交易

下面是表格结构

交易

id bigint(20) unsigned NO PRI auto_increment transfer_number bigint(20) 无符号 YES MUL debit_credit varchar(255) NO MUL fund_type varchar(255) NO MUL fund_id bigint(20) 无符号 YES MUL 货币 varchar(255) 否 金额小数(20,2) NO MUL 0 描述文字没有 other_type varchar(255) 否 other_id bigint(20) 无符号 YES transaction_type varchar(255) 否 account_receivable int(1) 无符号 NO 0 transaction_status varchar(255) NO MUL creation_date 日期时间 NO 0000-00-00 00:00:00 execution_date datetime NO MUL 0000-00-00 00:00:00 api int(1) 是 claim_id char(8) 是

帐户

id bigint(20) unsigned NO PRI auto_increment user_id bigint(20) 无符号 YES MUL account_number varchar(255) NO UNI type_id bigint(20) 无符号 YES MUL 描述 varchar(255) 否 Commission_acc_id bigint(20) 无符号 YES MUL allow_debit varchar(255) 否 allow_credit varchar(255) 否 account_status varchar(255) NO MUL creation_date 日期时间 NO 0000-00-00 00:00:00

帐户类型

id bigint(20) unsigned NO PRI auto_increment 描述 varchar(255) NO MUL 货币 varchar(255) NO MUL 月费金额双倍 NO 0 monthly_fee_description varchar(255) 否 yearly_fee_amount 双 NO 0 yearly_fee_description varchar(255) 否 generate_interests varchar(255) 否 利率双倍 NO 0 interest_payout_period varchar(255) 否 interest_payout_day char(2) 否 interest_payout_month char(2) 否 interest_payout_hour char(2) 否 interest_based_on varchar(255) 否 interest_based_on_period varchar(255) 否 interest_minimum_balance 双 NO 0 generate_commissions varchar(255) 否 佣金率双倍 NO 0 Commission_payout_period varchar(255) 否 Commission_payout_day char(2) 否 Commission_payout_month char(2) 否 Commission_payout_hour char(2) 否 Commission_based_on varchar(255) 否 Commission_based_on_period varchar(255) 否 Commission_minimum_balance double NO 0

以下是我们使用以下查询的查询:

SELECT SUM(t.amount) AS total_credit 
FROM    account_types at, 
        accounts a, 
        transactions t 
WHERE   at.currency          = var_currency 
AND     at.id                = a.type_id 
AND     (a.account_status    = 'active' 
        OR a.account_status  = 'blocked')
AND     a.id                 = t.fund_id 
AND     t.debit_credit       = var_debit_credit 
AND     t.fund_type          = 'account'
AND     t.transaction_status = 'executed';

这需要 20 分钟或更长时间才能得到输出。

管理层的先决条件 - 因为它是一个交易表,所以我们无法归档该表,我们需要记录来计算总和,而不是允许硬件更改。 有索引的表也存在。在描述中表示为 MUL。

【问题讨论】:

您能否发表一个解释,并告诉我们存在哪些索引? 这些是表上的索引 TRANSACTIONS id debit_credit fund_type amount transaction_status ACCOUNTS id type_id Commission_acc_id account_status ACCOUNT_TYPES id currency var_currencyvar_debit_credit 指的是哪里?它们是恒定的吗? 除了activeblocked 之外,还有其他帐户状态吗?还有多少? 没有解释,以及你已经拥有的确切索引,我们只能猜测...... 【参考方案1】:

首先,尝试在事务表中为您需要的所有列添加索引。

ALTER TABLE transaction
ADD INDEX `DebCredFundTypeTransStatus`
(`fund_id`,`debit_credit`,`fund_type`,`transaction_status`,`amount`)

这会将对该表的查找次数减少到仅针对该索引,而无需前往表本身获取数据。 amount 是索引的最右侧部分,这一点很重要。

由于a.account_statusat.currency 是它们各自表中唯一需要访问的列(除了主键,它包含在所有索引的最右边部分中),那么你应该可以接受这些。

下一个大瓶颈是 OR 子句。由于您没有订购您的结果,我们可以轻松地使用 UNION ALL 并为每个所需的 account_status 值运行两次。

SELECT SUM(t.amount) AS total_credit 
FROM    account_types at, 
        accounts a, 
        transactions t 
WHERE   at.currency          = var_currency 
AND     at.id                = a.type_id 
AND     a.account_status    = 'active'
AND     a.id                 = t.fund_id 
AND     t.debit_credit       = var_debit_credit 
AND     t.fund_type          = 'account'
AND     t.transaction_status = 'executed'

UNION ALL

SELECT SUM(t.amount) AS total_credit 
FROM    account_types at, 
        accounts a, 
        transactions t 
WHERE   at.currency          = var_currency 
AND     at.id                = a.type_id 
AND     a.account_status  = 'blocked'
AND     a.id                 = t.fund_id 
AND     t.debit_credit       = var_debit_credit 
AND     t.fund_type          = 'account'
AND     t.transaction_status = 'executed';

这些可能是最简单和最有成效的变化。试试看,看看情况是否有足够的改善。如果没有,可以应用其他优化。

【讨论】:

以上是关于查询性能问题 - 对于 select 语句,即使表上有超过 20 万亿条记录的索引的主要内容,如果未能解决你的问题,请参考以下文章

mysql之性能优化

回表查询的说明

MYSQL数据库性能调优之三:explain分析慢查询

select查询的性能

CASE WHEN SQL 查询在 else 中执行条件,即使第一个条件为真

sql语句:GRANT SELECT TO 数据库用户,该数据库用户是不是可以查阅所有表了?