如果将where字段添加到where,则查询会变慢

时间:2018-04-10 18:44:21

标签: mysql query-optimization

我有一张约有500k记录的表Mysql fiddle

CREATE TABLE IF NOT EXISTS `p_transactions` (
  `transaction_id` bigint(10) unsigned NOT NULL,
  `amount` decimal(19,2) NOT NULL,
  `dt` bigint(1) NOT NULL,
  `transaction_status` int(1) NOT NULL,
  `transaction_type` varchar(15) NOT NULL,
  `payment_method` varchar(25) NOT NULL,
  `notes` text NOT NULL,
  `member_id` int(10) unsigned NOT NULL,
  `new_amount` decimal(19,2) NOT NULL,
  `paid_amount` decimal(19,2) NOT NULL,
  `secret_code` char(40) NOT NULL,
  `internal_status` varchar(40) NOT NULL,
  `ip_addr` varchar(15) NOT NULL,
  `description` text NOT NULL,
  `seller_transaction_id` varchar(50) DEFAULT NULL,
  `return_url` varchar(255) DEFAULT NULL,
  `fail_url` varchar(255) DEFAULT NULL,
  `success_url` varchar(255) DEFAULT NULL,
  `result_url` varchar(255) DEFAULT NULL,
  `user_fee` decimal(19,3) DEFAULT '0.000',
  `currency` char(255) DEFAULT 'USD',
  `gateway_transaction_id` char(255) DEFAULT NULL,
  `load_amount` decimal(19,2) NOT NULL,
  `transaction_mode` varchar(1) NOT NULL DEFAULT '',
  `p_fee` decimal(19,2) NOT NULL,
  `country` varchar(2) NOT NULL,
  `email` varchar(255) NOT NULL,
  `vat` decimal(19,2) NOT NULL DEFAULT '0.00',
  `name` varchar(255) NOT NULL,
  `bdate` varchar(255) NOT NULL,
  `child_method` varchar(255) NOT NULL,
  `processing_fee` decimal(19,2) NOT NULL DEFAULT '0.00',
  `flat_fee` varchar(1) NOT NULL DEFAULT 'n',
  `user_fee_sum` decimal(19,2) NOT NULL DEFAULT '0.00',
  `p_fee_sum` decimal(19,2) NOT NULL DEFAULT '0.00',
  `dt_open` bigint(1) NOT NULL DEFAULT '0',
  `user_fee_type` varchar(1) NOT NULL DEFAULT 'r',
  `custom_gateway_fee` decimal(19,2) NOT NULL DEFAULT '0.00',
  `paid_currency` varchar(3) NOT NULL DEFAULT 'USD',
  `paid_microtime` bigint(10) unsigned NOT NULL,
  `check_ballance` varchar(1) NOT NULL DEFAULT 'n',
  PRIMARY KEY (`transaction_id`),
  KEY `member_id` (`member_id`),
  KEY `payment_method` (`payment_method`),
  KEY `child_method` (`child_method`),
  KEY `check_ballance` (`check_ballance`),
  KEY `dt` (`dt`),
  KEY `transaction_type` (`transaction_type`),
  KEY `paid_microtime` (`paid_microtime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

执行查询时

SELECT *
FROM `p_transactions`
WHERE dt >= 1517443200
AND dt <= 1523404799
AND member_id =  2051
ORDER BY `paid_microtime` DESC
 LIMIT 50;

它运行0,000秒。 (+ 0,016秒网络)

但如果我添加查询此条件AND transaction_status = 7

SELECT *
FROM `p_transactions`


WHERE dt >= 1517443200
AND dt <= 1523404799
AND member_id =  2051
AND transaction_status =  7

ORDER BY `paid_microtime` DESC
 LIMIT 50

查询运行12,938秒。 (+ 0,062秒网络)

请帮我找出这种行为的原因

PS。 transaction_status上有索引,它的执行时间也更长。

2 个答案:

答案 0 :(得分:1)

添加合适的索引,例如:

ON payzoff_transactions (member_id, dt) 

ON payzoff_transactions (member_id, dt, transaction_status)

我们希望member_id列作为索引中的前导列,因为相等比较,我们希望结果是整个表的一个小得多的子集。之后我们想要dt列,因为它上面有“范围扫描”。

在索引中包含其他列可能允许MySQL使用索引中的值检查该条件,而无需访问/查找基础表页中的行。

这些索引中的任何一个都适用于问题中显示的两个

使用EXPLAIN查看执行计划......正在使用哪个索引。

实际上没有解决“使用filesort”操作,因为我们正在拉动整个表格的一小部分。

(如果我们拉动整个表(或一个庞大的子集),我们可能能够避免昂贵的排序操作,其访问计划以反向索引顺序提取行,其中索引的前导列为{ {1}}。)

答案 1 :(得分:0)

对于原始查询有这些

INDEX(member_id, dt)
INDEX(member_id, paid_microtime)

对于辅助查询,请

INDEX(transaction_status, member_id, dt)
INDEX(transaction_status, member_id, paid_microtime)

没有深入了解数据值分布的细节,我们无法解释为什么一个查询这么慢;但是,我的4个索引应该使两个查询在大多数时间运行得更快。

更多关于我如何提出这些索引的讨论(以及为什么(member_id, dt, transaction_status)不太好):http://mysql.rjweb.org/doc.php/index_cookbook_mysql