用于从数据库返回新访问者的MySQL查询

use*_*146 1 mysql optimization

假设我有一个表记录每个用户拥有IP地址(ipaddr)的传入用户.

选择之前从未访问过网站的所有用户的最佳方法是什么?(这样特定的IPADDR值只存在于表中一次),但我只想知道过去6小时内出现的新访问者.

我基本上想在SQL中做这样的事情:

SELECT * from visitors GROUP BY ipaddr WHERE COUNT(ipaddr) = 1 and date > '2011-03-31 00:59:11'
Run Code Online (Sandbox Code Playgroud)

但是,DATE条件应仅适用于结果,而不适用于检查访问者是否是新的.

更新:

有一个SID字段可以解释用户浏览会话.

这是相关的表模式:

CREATE TABLE `visitors` (
  `date` timestamp NOT NULL default CURRENT_TIMESTAMP,
  `sid` bigint(12) unsigned NOT NULL,
  `ipaddr` int(8) NOT NULL,
)
Run Code Online (Sandbox Code Playgroud)

一些示例数据:

INSERT INTO `visitors` (`date`,`sid`, `ipaddr`)
VALUES
    ('2011-03-31 06:25:48', 299521885457, -1454342140);


INSERT INTO `visitors` (`date`,`sid`, `ipaddr`)
VALUES
    ('2011-03-31 06:26:37', 299521885457, -1454342140);


INSERT INTO `visitors` (`date`,`sid`, `ipaddr`)
VALUES
    ('2010-01-01 15:23:44', 694387538590, -1454342140);
Run Code Online (Sandbox Code Playgroud)

该访问者有两行实时发生当前会话,每行都是他访问过的每一页(仅显示相关的模式).显示的最后一个示例行是2010年的访问,这意味着此IP地址有2个不同的SID属于它,因此不是新访问者.

查询的结果应该没有上面列出的任何行,看看此访问者在数据库中有两个会话.如果删除了最后一行(使用sid 694387538590),则访问者应成为新访问者并显示在查询中.

man*_*nji 5

"WHERE"GROUP BYHAVING:

SELECT ipaddr from visitors
GROUP BY ipaddr
HAVING COUNT(ipaddr) = 1 AND MIN(date) > '2011-03-31 00:59:11'
Run Code Online (Sandbox Code Playgroud)

UPDATE

SELECT ipaddr, max(sid) sid
  FROM visitors
 GROUP BY ipaddr
HAVING     COUNT(DISTINCT sid) = 1
       AND MIN(date) > '2011-03-31 00:59:11'
Run Code Online (Sandbox Code Playgroud)

说明:

SELECT date, sid, ipaddr FROM visitors

date                sid        ipaddr 
------------------------------------------
2011-03-31 06:25:48 299525457  -1454342140 
2011-03-31 06:26:37 299525457  -1454342140 
2010-01-01 15:23:44 694388590  -1454342140 
2011-03-31 11:23:44 111111111  -1234444811 
2011-03-31 12:23:44 111111111  -1234444811

SELECT ipaddr FROM visitors GROUP BY ipaddr

ipaddr
-----------
-1454342140 
-1234444811 

--- group for ip -1454342140 ---

2011-03-31 06:25:48 299525457  -1454342140 
2011-03-31 06:26:37 299525457  -1454342140 
2010-01-01 15:23:44 694388590  -1454342140

COUNT(DISTINCT sid) = COUNT(299525457, 694388590) = 2
--> there is more than 1 session for this ip: not good!!!

  ==> group discarded

--- group for ip -1234444811 ---

2011-03-31 11:23:44 111111111  -1234444811 
2011-03-31 12:23:44 111111111  -1234444811

COUNT(DISTINCT sid) = COUNT(111111111) = 1 --> OK
(here COUNT(sid) = count(111111111, 111111111) = 2
 --> despite it is the same sid, the count is 2, that is why using DISTINCT)

MIN(date) = '2011-03-31 11:23:44' > '2011-03-31 00:59:11' --> OK

  ==> group accepted
Run Code Online (Sandbox Code Playgroud)

授权栏中SELECT有:

  • GROUP BY子句中使用的列
  • 其他专栏的聚集

ipaddr在GROUP BY中使用但不是sid.sid我也使用了MAX,但请记住它只会应用于当前的行组,ipaddr因为查询中的条件有1个唯一sid但重复的,所以结果将是sid