我有一张约有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
上有索引,它的执行时间也更长。
答案 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