我正在使用MySQL 5.7.25,这是我要优化的查询:
SELECT a.contract,
a.phone_number_1,
a.phone_number_2,
a.phone_number_3,
a.phone_number_4,
a.phone_number_5
FROM tempdb.customer_crm a
WHERE CHAR_LENGTH(a.contract) = 12
AND (
a.contract in (SELECT contract_final FROM tempdb.relevant_contracts)
OR a.phone_number_1 in (SELECT phone_number FROM tempdb.relevant_numbers_1)
OR a.phone_number_2 in (SELECT phone_number FROM tempdb.relevant_numbers_2)
OR a.phone_number_3 in (SELECT phone_number FROM tempdb.relevant_numbers_3)
OR a.phone_number_4 in (SELECT phone_number FROM tempdb.relevant_numbers_4)
OR a.phone_number_5 in (SELECT phone_number FROM tempdb.relevant_numbers_5)
);
customer_crm表在5列中有5个不同的电话号码。我需要筛选所有地方表的任何5个电话号码的存在记录relevant_numbers。我已经表5份relevant_numbers我只能使用临时表(不能在MySQL中打开不止一次)。中的记录数:
该查询花费的时间太长。我使用(电话号码长度条件)节省了几分钟:
SELECT a.contract,
a.phone_number_1,
a.phone_number_2,
a.phone_number_3,
a.phone_number_4,
a.phone_number_5
FROM tempdb.customer_crm a
WHERE CHAR_LENGTH(a.contract) = 12
AND (
a.contract in (SELECT contract_final FROM tempdb.relevant_contracts)
OR (CHAR_LENGTH(a.phone_number_1) > 9 AND a.phone_number_1 in (SELECT phone_number FROM tempdb.relevant_numbers_1))
OR (CHAR_LENGTH(a.phone_number_2) > 9 AND a.phone_number_2 in (SELECT phone_number FROM tempdb.relevant_numbers_2))
OR (CHAR_LENGTH(a.phone_number_3) > 9 AND a.phone_number_3 in (SELECT phone_number FROM tempdb.relevant_numbers_3))
OR (CHAR_LENGTH(a.phone_number_4) > 9 AND a.phone_number_4 in (SELECT phone_number FROM tempdb.relevant_numbers_4))
OR (CHAR_LENGTH(a.phone_number_5) > 9 AND a.phone_number_5 in (SELECT phone_number FROM tempdb.relevant_numbers_5))
);
仍然需要大约10分钟。我尝试使用EXISTS条件而不是IN,它花费的时间甚至更长。我也尝试过使用左连接,这也需要更长的时间。所有列均单独索引。
任何帮助将不胜感激。谢谢。
OR
是性能杀手。也是IN ( SELECT ... )
。
就目前而言,该查询将对80M行进行全表扫描,并在临时表中进行查找。如果您要为临时表建立索引,那么这些次要查询将只有1行,否则将只有63K行-总计将达到25万亿次查询。它可能在今年完成。
A计划:转OR
成UNION
:
( SELECT cc.id
FROM tempdb.customer_crm AS cc
JOIN tempdb.relevant_contracts AS rc
WHERE cc.contract = rc.contract
) UNION
( SELECT cc.id
FROM tempdb.customer_crm AS cc
JOIN tempdb.relevant_numbers_1 AS rn
WHERE cc.phone_number_1 = rn.phone_number
) UNION
( SELECT cc.id
FROM tempdb.customer_crm AS cc
JOIN tempdb.relevant_numbers_2 AS rn
WHERE cc.phone_number_2 = rn.phone_number
) UNION
( SELECT cc.id
FROM tempdb.customer_crm AS cc
JOIN tempdb.relevant_numbers_3 AS rn
WHERE cc.phone_number_3 = rn.phone_number
) UNION
( SELECT cc.id
FROM tempdb.customer_crm AS cc
JOIN tempdb.relevant_numbers_4 AS rn
WHERE cc.phone_number_4 = rn.phone_number
) UNION
( SELECT cc.id
FROM tempdb.customer_crm AS cc
JOIN tempdb.relevant_numbers_5 AS rn
WHERE cc.phone_number_5 = rn.phone_number
)
我假设id
是PRIMARY KEY
的customer_crm
。您将在以下位置使用这些索引customer_crm
:
INDEX(contract, id)
INDEX(phone_number_1, id)
INDEX(phone_number_2, id)
INDEX(phone_number_3, id)
INDEX(phone_number_4, id)
INDEX(phone_number_5, id)
将上面的查询用作子查询,JOIN
然后返回customer_crm
以获得您真正需要的任何列。
那将是大约一百万个动作-少得多。
长度= 12的检查稍后可能会引起小麻烦。
方案B:不要使用5列。
通常,将事物数组分布在多个列中或打包在一起放在一个列中通常是一个糟糕的方案设计。相反,要有另一个具有(至少)两列的表:thenumber
和theid
联接回主表。
使用INDEX(number)
,具有5 * 80M行并不重要。
计划C:创建临时表之前,您是否需要备份?其他优化也是可能的。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句