从慢查询日志中提高MySQL查询性能

时间:2016-03-30 21:13:35

标签: php mysql performance indexing

我在MySQL配置中打开了慢速查询监控器。

以下是查询和时间:

  

时间:160330 20:54:11   User @ Host:user [user] @ [xx.xx.xxx.xxx]   Query_time:8.794170 Lock_time:0.000141 Rows_sent:3942 Rows_examined:4742825   SET时间戳= 1459371251;

SELECT (SELECT (CASE WHEN ce_type = 'IN' then SUM(payment_amount)
                                END) as debit
                        FROM customer_payment_options cpo
                        WHERE wallet_id=cw.id
                        AND (cpo.real_account_type='HQ')
                        AND cpo.source_country_id='40'
                        GROUP BY cpo.wallet_id)
                    as debit,
                    (SELECT SUM(payment_amount)
                                 as credit
                        FROM customer_payment_options cpo
                        WHERE wallet_id=cw.id
                        AND (cpo.real_account_type='HQ')
                        AND cpo.tran_id IS NOT NULL
                        AND cpo.source_country_id='40'
                        GROUP BY cpo.wallet_id)
                    as credit

                    FROM customer_wallet cw
                    WHERE cw.company_id='1'
                    AND cw.currency='40'
                    AND cw.is_approved = '1'
                    AND DATE(cw.date_added) < '2016-03-30';

customer_payment_options上的索引:

company_id
tran_id
ce_id
wallet_id

我应该怎样做才能提高它的表现?

EXPLAIN

http://i.stack.imgur.com/iH8rt.png

SCHEMA

CREATE TABLE `customer_payment_options` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`company_id` int(11) NOT NULL,
`local_branch_id` int(11) NOT NULL,
`tran_id` bigint(11) DEFAULT NULL,
`ce_id` int(11) DEFAULT NULL,
`wallet_id` int(11) DEFAULT NULL,
`reward_credit_id` int(11) DEFAULT NULL,
`ce_invoice_id` varchar(32) DEFAULT NULL,
`ce_type` enum('IN','OUT') DEFAULT NULL,
`payment_type` enum('CASH','DEBIT','CREDIT','CHEQUE','DRAFT','BANK_DEPOSIT','EWIRE','WALLET','LOAN','REWARD_CREDIT') NOT NULL,
`payment_amount` varchar(20) NOT NULL,
`payment_type_number` varchar(100) DEFAULT NULL,
`source_country_id` int(11) NOT NULL,
`real_account_id` int(11) DEFAULT NULL,
`real_account_type` enum('LOCAL','HQ') DEFAULT NULL,
`date_added` datetime NOT NULL,
`event_type` enum('MONEY_TRANSFER','CURRENCY_EXCHANGE','WALLET') DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `company_id` (`company_id`),
KEY `real_account_type` (`real_account_type`),
KEY `tran_id` (`tran_id`),
KEY `ce_id` (`ce_id`),
KEY `wallet_id` (`wallet_id`),
CONSTRAINT `customer_payment_options_ibfk_4` FOREIGN KEY (`wallet_id`) REFERENCES `customer_wallet` (`id`),
CONSTRAINT `customer_payment_options_ibfk_1` FOREIGN KEY (`company_id`) REFERENCES `company` (`id`),
CONSTRAINT `customer_payment_options_ibfk_2` FOREIGN KEY (`tran_id`) REFERENCES `transaction` (`id`),
CONSTRAINT `customer_payment_options_ibfk_3` FOREIGN KEY (`ce_id`) REFERENCES `currency_exchange` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=412 DEFAULT CHARSET=utf8

CREATE TABLE `customer_wallet` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`wallet_unique_id` varchar(100) DEFAULT NULL,
`company_id` int(11) NOT NULL,
`branch_admin_id` int(11) DEFAULT NULL,
`emp_id` int(11) DEFAULT NULL,
`emp_type` enum('SUPER_ADMIN','ADMIN','AGENT_ADMIN','AGENT','OVER_AGENT_ADMIN','OVER_AGENT') DEFAULT NULL,
`cus_id` bigint(11) NOT NULL,
`tran_id` bigint(11) DEFAULT NULL,
`beehive_id` int(11) DEFAULT NULL,
`type` enum('DEPOSIT','WITHDRAW','TRANSACTION') NOT NULL,
`sub_type` enum('MONEY_TRANSFER','BEEHIVE_DEPOSIT') DEFAULT NULL,
`credit_in` varchar(20) DEFAULT NULL,
`credit_out` varchar(20) DEFAULT NULL,
`currency` varchar(20) NOT NULL,
`date_added` datetime NOT NULL,
`note` varchar(255) DEFAULT NULL,
`location` enum('DIRECT') DEFAULT NULL,
`is_approved` enum('0','1') NOT NULL DEFAULT '1',
`idebit_issconf` varchar(50) DEFAULT NULL,
`idebit_issname` varchar(50) DEFAULT NULL,
`idebit_isstrack2` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `cus_id` (`cus_id`),
KEY `company_id` (`company_id`),
KEY `branch_admin_id` (`branch_admin_id`),
KEY `emp_id` (`emp_id`),
KEY `tran_id` (`tran_id`),
KEY `beehive_id` (`beehive_id`),
CONSTRAINT `customer_wallet_ibfk_1` FOREIGN KEY (`cus_id`) REFERENCES `customers` (`id`),
CONSTRAINT `customer_wallet_ibfk_2` FOREIGN KEY (`company_id`) REFERENCES `company` (`id`),
CONSTRAINT `customer_wallet_ibfk_3` FOREIGN KEY (`tran_id`) REFERENCES `transaction` (`id`),
CONSTRAINT `customer_wallet_ibfk_4` FOREIGN KEY (`emp_id`) REFERENCES `employees` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=152 DEFAULT CHARSET=utf8

2 个答案:

答案 0 :(得分:3)

您正在做什么作为每个钱包ID的相关查询,以获得相应的借记和信用。看来你的每个钱包ID都有一条记录。这很忙。根据您的标准(包括每个钱包ID的加入)加入客户付款表。然后,将CASE简化为SUM(case / when)作为相应的借方/贷方。

我不知道你的表格列的基本标准,但我甚至会对(而且确实)包括不包括CE_TYPE ='IN',因为这看起来是借记的基础,你不会错误地算作一部分也是一种信用。再次,不知道字段,trans_id,类型的相关性。

现在,如上所述,在单个字段上使用单个索引无助于优化此查询。我会建议以下索引。

表索引 customer_wallet(company_id,is_approved,currency,id,date_added) customer_payment_options(wallet_id,account_type,country_id)

SELECT
      cw.wallet_id,
      SUM( case when cpo.ce_type = 'IN'
                then cpo.payment_amount
                ELSE 0 end ) as Debit,
      SUM( case when NOT cpo.ce_type = 'IN' 
                     AND cpo.tran_id IS NOT NULL
                then cpo.payment_amount
                ELSE 0 end ) as Credit
   FROM 
      customer_wallet cw
         JOIN customer_payment_options cpo
            ON cw.id = cpo.wallet_id
           AND cpo.real_account_type = 'HQ'
           AND cpo.source_country_id = '40'
   WHERE 
          cw.company_id = '1'
      AND cw.currency = '40'
      AND cw.is_approved = '1'
      AND cw.date_added < '2016-03-30'
   GROUP BY
      cw.id

另外一条评论。如果您的ID列,货币标记,国家/地区ID,已批准实际上是表结构中的数值,请删除引号并直接比较数值。另外,对于你的date_added。你有基于DATE(date_added)的那个。对列执行功能无法充分利用索引。由于date()剥离了日期/时间戳列的任何时间部分,并且您要求所有添加的数量少于3月30日,因此3月29日晚上11:59:59的添加日期仍然低于3月30日12:凌晨00:00,所以不需要转换日期。

正如Ivan(下文)所评论的,如果您想要所有电子钱包ID,无论是否有任何付款(借记或贷记),请从联接更改为LEFT JOIN。

答案 1 :(得分:0)

您需要添加索引和多列索引以使其快速。 请记住,如果你有大表,额外的索引将减慢插入速度,因为索引文件更新将花费更多的时间。

  

如果col1和col2上存在多列索引,则相应   行可以直接获取。如果存在单独的单列索引   在col1和col2上,优化器尝试使用索引合并   优化(参见第8.2.1.4节“索引合并优化”)或   试图通过决定哪个索引来找到最严格的索引   排除更多行并使用该索引来获取行。

     

如果表有多列索引,则表示最左边的前缀   优化器可以使用index来查找行。例如,如果   你有一个三列索引(col1,col2,col3),你已编入索引   搜索(col1),(col1,col2)和(col1,col2,col3)的功能。

Read more