如果将字段添加到where条件,查询速度会减慢

31moq8wy  于 2021-06-24  发布在  Mysql
关注(0)|答案(2)|浏览(326)

我有一张table,上面有大约50万条记录。

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;

它运行0000秒。(+0016秒。网络)
但如果我加上这个条件 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

查询运行12938秒。(+0062秒。网络)
请帮我找出这种行为的原因
另外,上面有索引 `transaction_status` 而且它更增加了执行时间。
xbp102n0

xbp102n01#

添加适当的索引,例如:

ON payzoff_transactions (member_id, dt)

或者

ON payzoff_transactions (member_id, dt, transaction_status)

我们想要 member_id 列作为索引中的前导列,因为相等比较,我们期望结果是整个表的一个小得多的子集。我们想要 dt 列之后,因为“范围扫描”上说。
在索引中包含额外的列可以允许mysql使用索引中的值来检查该条件,而无需访问/查找底层表页中的行。
这些索引中的任何一个都适用于问题中显示的两个查询。
使用 EXPLAIN 看看执行计划。。。正在使用哪个索引。
“usingfilesort”操作实际上是绕不开的,因为我们要提取整个表的一小部分。
(如果我们拉取整个表(或一个巨大的子集),我们可能能够避免一个昂贵的排序操作,因为访问计划按反向索引顺序拉取行,并且索引的前导列为 paid_microtime .)

yrefmtwq

yrefmtwq2#

对于原始查询

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

相关问题