0

由于需要使用 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 封电子邮件(类别 = 电子邮件名称)中每封电子邮件的最新状态列表。我只需要该用户的每个人的最新状态。例如,使用“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 专业人士。

4

3 回答 3

2

您可以做的一项优化是执行以下操作:

  1. 首先 AES 加密提供电子邮件地址的参数
  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而不是只加密参数,并使用它进行测试..

于 2013-03-20T20:16:55.480 回答
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以防多个类别匹配。

于 2013-03-20T20:18:57.783 回答
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
)
于 2013-03-20T20:23:35.710 回答