我正在使用开放式ID登录审核我的应用程序中的用户详细信息。如果用户第一次登录我们认为是注册的OPEN ID。我正在使用此详细信息生成审计登录报告。样本表数据。
+---------+----------+-----------+---------------+
| USER_ID | PROVIDER | OPERATION | TIMESTAMP |
+---------+----------+-----------+---------------+
| 120 | Google | SIGN_UP | 1347296347000 |
| 120 | Google | SIGN_IN | 1347296347000 |
| 121 | Yahoo | SIGN_IN | 1347296347000 |
| 122 | Yahoo | SIGN_IN | 1347296347000 |
| 120 | Google | SIGN_UP | 1347296347000 |
| 120 | FaceBook | SIGN_IN | 1347296347000 |
+---------+----------+-----------+---------------+
在此表中,我想要排除 SIGN_UP ed" SIGN_IN "基于提供者的ed用户数。
显示创建表格
CREATE TABLE `signin_details` (
`USER_ID` int(11) DEFAULT NULL,
`PROVIDER` char(40) DEFAULT NULL,
`OPERATION` char(40) DEFAULT NULL,
`TIMESTAMP` bigint(20) DEFAULT NULL
) ENGINE=InnoDB
我正在使用此查询。
select
count(distinct(USER_ID)) as signin_count,
PROVIDER from signin_details s1
where
s1.USER_ID NOT IN
(
select
USER_ID
from signin_details
where
signin_details.PROVIDER=s1.PROVIDER
and signin_details.OPERATION='SIGN_UP'
and signin_details.TIMESTAMP/1000 BETWEEN UNIX_TIMESTAMP(CURRENT_DATE()-INTERVAL 1 DAY) * 1000 AND UNIX_TIMESTAMP(CURRENT_DATE()) * 1000
)
AND OPERATION='SIGN_IN' group by PROVIDER;
解释输出:
+----+--------------------+----------------+------+---------------+------+---------+------+------+-----------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+----------------+------+---------------+------+---------+------+------+-----------------------------+
| 1 | PRIMARY | s1 | ALL | NULL | NULL | NULL | NULL | 6 | Using where; Using filesort |
| 2 | DEPENDENT SUBQUERY | signin_details | ALL | NULL | NULL | NULL | NULL | 6 | Using where |
+----+--------------------+----------------+------+---------------+------+---------+------+------+-----------------------------+
查询输出:
+--------------+----------+
| signin_count | PROVIDER |
+--------------+----------+
| 1 | FaceBook |
| 2 | Yahoo |
+--------------+----------+
执行20万行需要40多分钟。
我的假设是它会检查每一行的从属子查询输出的总数。
我对此查询的假设。
A -> Dependant Outputs (B,C,D) .
A check with B
A check with C
A check with D
如果依赖查询输出较大,则执行需要很长时间。如何改进此查询?
答案 0 :(得分:4)
如果您使用 MySQL ,您必须知道子查询的执行速度非常慢。
IN
很慢......
EXISTS
通常比IN
JOIN
主要是做这类事情的最快方式。
SELECT DISTINCT
s1.PROVIDER,
COUNT(DISTINCT s1.USER_ID)
FROM
signin_details s1
LEFT JOIN
(
SELECT DISTINCT
USER_ID, PROVIDER
FROM
signin_details
WHERE
signin_details.OPERATION='SIGN_UP'
AND
signin_details.TIMESTAMP
BETWEEN
UNIX_TIMESTAMP(CURRENT_DATE()-INTERVAL 1 DAY) * 1000
AND UNIX_TIMESTAMP(CURRENT_DATE()) * 1000
) AS t USING (USER_ID, PROVIDER)
WHERE
t.USER_ID IS NULL
AND OPERATION='SIGN_IN'
GROUP BY s1.PROVIDER
http://sqlfiddle.com/#!2/122ac/12
注意:如果您想知道sqlfiddle结果,请考虑查询中的UNIX_TIMESTAMP
。
结果:
| PROVIDER | COUNT(DISTINCT S1.USER_ID) |
-----------------------------------------
| FaceBook | 1 |
| Yahoo | 2 |
MySQL和INTERSECT
故事。您获得了USER_ID
和PROVIDER
的所有组合,您不想计算这些组合。然后LEFT JOIN
将它们添加到您的数据中。现在,您想要计算的所有行都没有来自LEFT JOIN
的值。你可以通过t.USER_ID IS NULL
获得它们。
输入:
| rn° | USER_ID | PROVIDER | OPERATION | TIMESTAMP |
-------------------------------------------------------
| 1 | 120 | Google | SIGN_UP | 1347296347000 | -
| 2 | 120 | Google | SIGN_IN | 1347296347000 | - (see rn° 1)
| 3 | 121 | Yahoo | SIGN_IN | 1347296347000 | Y
| 4 | 122 | Yahoo | SIGN_IN | 1347296347000 | Y
| 5 | 120 | Google | SIGN_UP | 1347296347000 | -
| 6 | 120 | FaceBook | SIGN_IN | 1347296347000 | F
| 7 | 119 | FaceBook | SIGN_IN | 1347296347000 | - (see rn° 8)
| 8 | 119 | FaceBook | SIGN_UP | 1347296347000 | -
答案 1 :(得分:0)
在HAVING子句中使用“ NOT IN”。 它会比“不在那里”更快