由于需要使用AES_DECRYPT以及其他一些棘手的情况,我有一个非常棘手的SQL查询需要很长时间。首先,这是查询:
SELECT
CONVERT( AES_DECRYPT( email, '$key' ) USING UTF8 ),
timestamp,
category,
status
FROM email_statuses
WHERE
timestamp IN (
SELECT MAX(timestamp)
FROM email_statuses
WHERE ( CONVERT( AES_DECRYPT( email, '$key' ) USING UTF8 ) = ?
OR CONVERT( AES_DECRYPT( email, '$key' ) USING UTF8 ) = ? )
AND category = 'EMAIL_TEMPLATE_01'
)
OR
timestamp IN (
SELECT MAX(timestamp)
FROM email_statuses
WHERE ( CONVERT( AES_DECRYPT( email, '$key' ) USING UTF8 ) = ?
OR CONVERT( AES_DECRYPT( email, '$key' ) USING UTF8 ) = ? )
AND category = 'EMAIL_TEMPLATE_02'
)
OR
timestamp IN (
SELECT MAX(timestamp)
FROM email_statuses
WHERE ( CONVERT( AES_DECRYPT( email, '$key' ) USING UTF8 ) = ?
OR CONVERT( AES_DECRYPT( email, '$key' ) USING UTF8 ) = ? )
AND category = 'EMAIL_TEMPLATE_03'
);
在每个块中都显示时间戳IN(...第一个?是用户的主电子邮件,第二个?是用户的辅助电子邮件。
此查询的基本操作是返回3封电子邮件中每一封邮件的最新状态列表(category =电子邮件的名称)。对于该用户,我只需要每个LATEST状态。例如,使用“email@domain.com”的查询结果可能如下所示:
email---------------timestamp----------category-------------status---------
email@domain.com----0000-00-00 etc-----EMAIL_TEMPLATE_01----Sent
email@domain.com----0000-00-00 etc-----EMAIL_TEMPLATE_02----Open & click through
email@domain.com----0000-00-00 etc-----EMAIL_TEMPLATE_03----Open
由于email_status表现在超过1000条记录,因此查询最多需要30秒,因为它需要在状态表中的每个加密电子邮件行上运行convert / AES_DECRYPT。有关优化方法的任何想法?我不是一个SQL专业人士。
答案 0 :(得分:2)
您可以做的一件事就是执行以下操作:
因此,每个查询都会变成:
// precompute the encrypted parameter (maybe on the PHP side, before executing the query)
SELECT MAX(timestamp)
FROM email_statuses
WHERE email = ? -- here pass the already encrpyed paramter
OR email = ? -- .. same here
AND category = 'EMAIL_TEMPLATE_02'
基本思路是避免在查询中对每个测试执行AES_ENCRYPT
或AES_DECRYPT
。而只是加密参数,并使用它进行测试..
答案 1 :(得分:2)
将所有in
语句合并到一个联接中:
SELECT distinct CONVERT( AES_DECRYPT( es.email, '$key' ) USING UTF8 ),
es.timestamp, es.category, es.status
FROM email_statuses es join
(select category, MAX(timestamp) as maxtimestamp
from email_statuses
where ( CONVERT( AES_DECRYPT( email, '$key' ) USING UTF8 ) = ? or
CONVERT( AES_DECRYPT( email, '$key' ) USING UTF8 ) = ? ) and
category in ('EMAIL_TEMPLATE_01', 'EMAIL_TEMPLATE_02', 'EMAIL_TEMPLATE_03')
group by category
) csum
on es.timestamp = csum.category
我还添加了distinct
,以防多个类别匹配。
答案 2 :(得分:1)
由于您有三个子查询,每个子查询都必须解密所有记录。如果你可以在一个子查询中执行此操作,则应该花费三分之一时间。
SELECT CONVERT( AES_DECRYPT( email, '$key' ) USING UTF8 ),
timestamp, category, status
FROM email_statuses
WHERE
timestamp IN (
SELECT MAX(timestamp)
FROM email_statuses
WHERE ( CONVERT( AES_DECRYPT( email, '$key' ) USING UTF8 ) = ?
OR CONVERT( AES_DECRYPT( email, '$key' ) USING UTF8 ) = ? )
AND category IN ('EMAIL_TEMPLATE_01', 'EMAIL_TEMPLATE_02', 'EMAIL_TEMPLATE_03')
GROUP BY category
)