我有一张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` 而且它更增加了执行时间。
2条答案
按热度按时间xbp102n01#
添加适当的索引,例如:
或者
我们想要
member_id
列作为索引中的前导列,因为相等比较,我们期望结果是整个表的一个小得多的子集。我们想要dt
列之后,因为“范围扫描”上说。在索引中包含额外的列可以允许mysql使用索引中的值来检查该条件,而无需访问/查找底层表页中的行。
这些索引中的任何一个都适用于问题中显示的两个查询。
使用
EXPLAIN
看看执行计划。。。正在使用哪个索引。“usingfilesort”操作实际上是绕不开的,因为我们要提取整个表的一小部分。
(如果我们拉取整个表(或一个巨大的子集),我们可能能够避免一个昂贵的排序操作,因为访问计划按反向索引顺序拉取行,并且索引的前导列为
paid_microtime
.)yrefmtwq2#
对于原始查询
对于二次查询,有
如果不深入了解数据值分布的细节,我们就无法解释为什么一个查询会慢得多;但是,我的4个索引应该使这两个查询在大多数情况下运行得更快。
更多关于我是如何提出这些索引的讨论(以及为什么)
(member_id, dt, transaction_status)
不太好):http://mysql.rjweb.org/doc.php/index_cookbook_mysql