是否可以优化此查询?它看起来多余:
SELECT
SUM((SELECT
IFNULL(SUM(trx.totalAmount), 0)
FROM trx
WHERE
FIND_IN_SET (trx.clientOrderId, "B6A8DB9568,6E7705B487,59C4D4234D,1D9CD4EF96,4C373E8CDE,E818BEE48F,6610555669,ECF388E288,32FD93075C,B03417425B,18FD77061A,1C39E4BD04,C92B970E55,0920F06DFA,EEFB4AAADA,FC2D9FF9AD") > 0
AND trx.txnType IN ('REFUND', 'VOID')
)) as refunds,
SUM((SELECT
IFNULL(SUM(trx.totalAmount), 0)
FROM trx
WHERE
FIND_IN_SET (trx.clientOrderId, "B6A8DB9568,6E7705B487,59C4D4234D,1D9CD4EF96,4C373E8CDE,E818BEE48F,6610555669,ECF388E288,32FD93075C,B03417425B,18FD77061A,1C39E4BD04,C92B970E55,0920F06DFA,EEFB4AAADA,FC2D9FF9AD") > 0
AND trx.txnType = 'SALE'
AND trx.billingCycleNumber != 1
)) AS lifetimeRevenue
请注意,这只是查询的一部分,原始查询中还有10个以上,所以真的需要知道它是否可以优化。
谢谢你们。
答案 0 :(得分:0)
使用这样的子查询的问题是每个子查询都必须扫描整个表。即使您有索引,使用FIND_IN_SET()的方式也会强制执行完整的表扫描。所以你正在进行12次全表扫描。
这是一个根本不使用子查询的解决方案。它会在表中扫描匹配的clientOrderId值一次,以获取与您需要的任何txType匹配的所有行的超集。
然后,如果txnType是某些类型之一,则totalAmount的每个总和都是有条件的,否则对每行的totalAmount使用零,并且零对总和没有贡献,所以它就好像你已跳过不匹配的txnType行。
SELECT
SUM(IF(trx.txnType IN ('REFUND', 'VOID'), trx.totalAmount, 0)) AS refunds,
SUM(IF(trx.txnType = 'SALE' AND trx.billingCycleNumber != 1, trx.totalAmount, 0)) AS lifetimeRevenue
FROM trx
WHERE trx.clientOrderId IN (
'B6A8DB9568', '6E7705B487', '59C4D4234D', '1D9CD4EF96',
'4C373E8CDE', 'E818BEE48F', '6610555669', 'ECF388E288',
'32FD93075C', 'B03417425B', '18FD77061A', '1C39E4BD04',
'C92B970E55', '0920F06DFA', 'EEFB4AAADA', 'FC2D9FF9AD')
AND trx.txnType IN ('REFUND', 'VOID', 'SALE');
此查询应该有(clientOrderId)索引。由于您有两个IN()
谓词,因此WHERE子句只会使用索引中第一列的索引。
不要使用FIND_IN_SET()表达式,因为它不会使用WHERE子句的索引。
你说在查询中还有10个术语。所以我预计这些术语中会有一些不同类型的表达。我不会回答任何问题,但如果下一个条款看起来像是不同的话会怎样......"。我已经向您展示了将子查询解析为一个单遍查询的方法。将其应用于查询中的其他字词取决于您。
这是我测试的一个演示:
create table trx (
clientOrderId char(10),
txnType enum('REFUND','VOID','SALE'),
totalAmount numeric(9,2),
billingCycleNumber int default 0,
key (clientOrderId)
);
+---------------+---------+-------------+--------------------+
| clientOrderId | txnType | totalAmount | billingCycleNumber |
+---------------+---------+-------------+--------------------+
| B6A8DB9568 | REFUND | 42.00 | 0 |
| 59C4D4234D | SALE | 84.00 | 0 |
+---------------+---------+-------------+--------------------+
这里是您的查询的EXPLAIN:
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
| 1 | PRIMARY | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used |
| 3 | SUBQUERY | trx | NULL | ALL | NULL | NULL | NULL | NULL | 2 | 50.00 | Using where |
| 2 | SUBQUERY | trx | NULL | ALL | NULL | NULL | NULL | NULL | 2 | 50.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
注意每个术语的一个子查询,每个术语都执行" type = All"作为表访问。
这是我的查询的EXPLAIN:
+----+-------------+-------+------------+-------+---------------+---------------+---------+------+------+----------+------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------------+---------+------+------+----------+------------------------------------+
| 1 | SIMPLE | trx | NULL | range | clientOrderId | clientOrderId | 11 | NULL | 16 | 50.00 | Using index condition; Using where |
+----+-------------+-------+------------+-------+---------------+---------------+---------+------+------+----------+------------------------------------+
使用索引进行一次简单的表访问。
根据我尝试的示例数据,查询和查询的结果:
+---------+-----------------+
| refunds | lifetimeRevenue |
+---------+-----------------+
| 42.00 | 84.00 |
+---------+-----------------+