我使用NOT IN但它很慢

时间:2017-12-27 11:58:27

标签: mysql sql

CRM 表示例:

`crm` example:
+----+--------+---------------------+--------------------+
| id | name   |         date        |      status        |
+----+--------+---------------------+--------------------+
| 1  | john   | 2017-12-27 10:58:10 | A status           |
| 2  | steve  | 2017-12-27 10:58:08 | A status           |
| 3  | eric   | 2017-12-27 10:58:04 | Delivery Arranged  |
| 4  | phil   | 2017-12-27 10:57:55 | A status           |
| 5  | bob    | 2017-12-27 10:57:52 | A status           |
| 6  | foo    | 2017-12-27 10:57:50 | A status           |
| 7  | steven | 2017-12-27 10:57:48 | Delivery Arranged  |
| 8  | paul   | 2017-12-27 10:57:43 | A status           |
| 9  | alex   | 2017-12-27 10:57:31 | Delivery Arranged  |

我的查询对象是返回crm 交付安排status行数,date介于{{1}之间}和2017-12-01

所以,这是我的主要查询

2018-01-01

结果:

SET @from='2017-12-01';
SET @to='2018-01-01';


SELECT 
        COUNT(*) AS `delivery_arranged`
    FROM
        `crm` a
    WHERE
        a.`status` = 'Delivery Arranged'
            AND DATE(a.`date`) BETWEEN @from AND @to

一切都好。但是我希望打折那些之前曾经(实际上除此日期范围之外)的行已设置为交付安排。我有一个 statuslog 表,我可以用它:

STATUSLOG 表示例:

+---------------------+
|   delivery_arranged |
+---------------------+
| 30                  |

因此,使用此表格,我可以从`statuslog` example: +--------+-------+---------------------+-----------+---------------------+ | id | crmid | date | user | status | +--------+-------+---------------------+-----------+---------------------+ | 818572 | 1 | 2017-12-27 10:58:10 | johnsmith | Some status change | | 818571 | 2 | 2017-12-27 10:58:08 | johnsmith | Some status change | | 818570 | 3 | 2017-12-27 10:58:04 | another | Delivery Arranged | | 818569 | 4 | 2017-12-27 10:57:55 | another | Delivery Arranged | | 818568 | 5 | 2017-12-27 10:57:52 | johnsmith | Some status change | | 818567 | 6 | 2017-12-27 10:57:50 | another | Some status change | | 818566 | 7 | 2017-12-27 10:57:48 | johnsmith | Delivery Arranged | | 818565 | 8 | 2017-12-27 10:57:43 | another | Some status change | | 818564 | 9 | 2017-12-27 10:57:31 | johnsmith | Some status change | 获取不在日期范围之间的行,然后执行statuslog

NOT IN

这可行,但根据日期范围的大小,它可能需要很长时间! SELECT COUNT(*) AS `delivery_arranged` FROM `crm` a WHERE a.`status` = 'Delivery Arranged' AND DATE(a.`date`) BETWEEN @from AND @to AND a.`id` NOT IN ( SELECT a.crmid AS `crmid` FROM statuslog a WHERE a.status = 'Delivery Arranged' AND DATE(a.`date`) NOT BETWEEN @from AND @to GROUP BY a.crmid ORDER BY a.`date` DESC ) 有> 2,000,000行。

如何更快地进行此查询?

2 个答案:

答案 0 :(得分:0)

如果您使用cli packages: (C:\Users\Houssem\AppData\Roaming\npm\node_modules) @ionic/cli-utils : 1.19.0 ionic (Ionic CLI) : 3.19.0 global packages: cordova (Cordova CLI) : 7.1.0 local packages: @ionic/app-scripts : 3.1.4 Cordova Platforms : android 6.3.0 Ionic Framework : ionic-angular 3.9.2 System: Android SDK Tools : 26.1.1 Node : v8.9.3 npm : 5.5.1 OS : Windows 10 Environment Variables: ANDROID_HOME : C:\Users\Houssem\AppData\Local\Android\sdk Misc: backend : pro / LEFT JOIN

,通常会更快
WHERE

对于此版本,您需要SELECT COUNT(*) AS delivery_arranged FROM crm c LEFT JOIN statuslog sl ON sl.crmid = c.id AND sl.status = 'Delivery Arranged' sl.date >= @from AND sl.date < @to + INTERVAL 1 DAY WHERE c.status = 'Delivery Arranged' AND c.date >= @from AND c.date < @to + INTERVAL 1 DAY AND sl.crmid IS NULL; crm(status, date, id)上的索引。

请注意,这会更改日期比较以避免对列进行函数调用。这使得使用包含statuslog(crmid, status, date)列的索引更为可行。

答案 1 :(得分:0)

左连接可能比代理子查询更好:

date

另外,请记住使用正确的索引。