查询性能问题 - 对于 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 currencyvar_currency
和 var_debit_credit
指的是哪里?它们是恒定的吗?
除了active
或blocked
之外,还有其他帐户状态吗?还有多少?
没有解释,以及你已经拥有的确切索引,我们只能猜测......
【参考方案1】:
首先,尝试在事务表中为您需要的所有列添加索引。
ALTER TABLE transaction
ADD INDEX `DebCredFundTypeTransStatus`
(`fund_id`,`debit_credit`,`fund_type`,`transaction_status`,`amount`)
这会将对该表的查找次数减少到仅针对该索引,而无需前往表本身获取数据。 amount
是索引的最右侧部分,这一点很重要。
由于a.account_status
和at.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 万亿条记录的索引的主要内容,如果未能解决你的问题,请参考以下文章