Mysql - 每天、每月、每年和总计计数器 Web 访问的 SQL 查询

Lea*_*ing 2 php mysql database

我正在制作一个系统来计算我的网站的访问量,然后将其显示在图表类型上。

例如,我想通过以下方式获取所有访问:

  1. 今天的网络访问者总数

SELECT COUNT(DISTINCT ip) FROM visits_website WHERE DATE_FORMAT(create_at, '%Y-%m-%d') = CURDATE()) AS total_today

  1. 一个小时的网站总访问量

SELECT COUNT(DISTINCT ip) FROM visits_website WHERE create_at >= DATE_SUB(NOW(), INTERVAL 1 HOUR)) AS total_before_hours

  1. 昨天的总网站访问量

SELECT COUNT(DISTINCT ip) FROM visits_website WHERE create_at >= DATE_SUB(NOW(), INTERVAL 1 DAY)) AS total_yesterday

  1. 一周的总访问量网站

SELECT COUNT(DISTINCT ip) FROM visits_website WHERE YEARWEEK(create_at, 1) = YEARWEEK(CURDATE(), 1)) AS total_week

  1. 上周网站总访问量

SELECT COUNT(DISTINCT ip) FROM visits_website WHERE create_at >= DATE_SUB(NOW(), INTERVAL 1 WEEK)) AS total_last_weekend

  1. 网站总访问量 月

SELECT COUNT(DISTINCT ip) FROM visits_website WHERE MONTH(create_at) = MONTH(NOW())) AS total_month

  1. 上个月网站总访问量

SELECT COUNT(DISTINCT ip) FROM visits_website WHERE create_at >= DATE_SUB(NOW(), INTERVAL 1 MONTH)) AS total_last_month

  1. 全年网络访问总量

SELECT COUNT(DISTINCT ip) FROM visits_website WHERE YEAR(create_at) = YEAR(CURDATE())) AS total_year

我在一个MySql表中注册了访问网站,我想得到这个表在指定时间段内收到的所有不同IP访问的网站,我已经与MySql[DATE_SUB]函数进行了多次协商,因为不得不多次更改为一些查询:

这些是我为所有访问所做的查询:

SELECT 
COUNT(DISTINCT ip) AS total,
(SELECT COUNT(DISTINCT ip) FROM visits_website WHERE create_at  >= DATE_SUB(NOW(), INTERVAL 1 HOUR)) AS total_before_hours,
(SELECT COUNT(DISTINCT ip) FROM visits_website WHERE DATE_FORMAT(create_at, '%Y-%m-%d') = CURDATE()) AS total_today,
(SELECT COUNT(DISTINCT ip) FROM visits_website WHERE create_at  >= DATE_SUB(NOW(), INTERVAL 1 DAY)) AS total_yesterday,
(SELECT COUNT(DISTINCT ip) FROM visits_website WHERE YEARWEEK(`create_at`, 1) = YEARWEEK(CURDATE(), 1)) AS total_week,
(SELECT COUNT(DISTINCT ip) FROM visits_website WHERE create_at  >= DATE_SUB(NOW(), INTERVAL 1 WEEK)) AS total_last_weekend,
(SELECT COUNT(DISTINCT ip) FROM visits_website WHERE MONTH(`create_at`) = MONTH(NOW())) AS total_month,
(SELECT COUNT(DISTINCT ip) FROM visits_website WHERE create_at  >= DATE_SUB(NOW(), INTERVAL 1 MONTH)) AS total_last_month,
(SELECT COUNT(DISTINCT ip) FROM visits_website WHERE YEAR(`create_at`) = YEAR(CURDATE())) AS total_year
FROM visits_website
Run Code Online (Sandbox Code Playgroud)

我想知道以下内容:

  1. 是这些最佳的 mysql 查询和制作这个系统的最佳方式吗?
  2. 这是一个很好的开发实践,表中需要更多的索引。

表代码:

CREATE TABLE IF NOT EXISTS `visits_website` (
    `id` BIGINT UNSIGNED AUTO_INCREMENT,
    `ip` VARCHAR(25) NOT NULL,
    `browser_short` VARCHAR(45) NOT NULL,
    `browser_long` VARCHAR(255) NOT NULL,
    `create_at` DATETIME NOT NULL,
    PRIMARY KEY (`id`),
    INDEX `FK_visits_website` (`ip`)
)Engine=InnoDB;

INSERT INTO `visits_website` VALUES ('1', 'ip1', 'ip1', '', '2016-08-31 20:30:00');
INSERT INTO `visits_website` VALUES ('2', 'ip1', 'ip1', '', '2016-08-31 20:30:00');
INSERT INTO `visits_website` VALUES ('3', 'ip2', 'ip2', '', '2016-08-31 19:30:00');
INSERT INTO `visits_website` VALUES ('4', 'ip1', 'ip1', '', '2016-08-31 19:30:00');
INSERT INTO `visits_website` VALUES ('5', 'ip2', 'ip2', '', '2016-08-31 18:30:00');
INSERT INTO `visits_website` VALUES ('6', 'ip3', 'ip3', '', '2016-08-31 18:30:00');
INSERT INTO `visits_website` VALUES ('7', 'ip1', 'ip1', '', '2016-08-31 17:30:00');
INSERT INTO `visits_website` VALUES ('8', 'ip2', 'ip2', '', '2016-08-31 17:30:00');
INSERT INTO `visits_website` VALUES ('9', 'ip3', 'ip3', '', '2016-08-31 16:30:00');
INSERT INTO `visits_website` VALUES ('10', 'ip4', 'ip4', '', '2016-08-31 16:30:00');
INSERT INTO `visits_website` VALUES ('11', 'ip1', 'ip1', '', '2016-08-30 20:30:00');
INSERT INTO `visits_website` VALUES ('12', 'ip2', 'ip2', '', '2016-08-30 20:30:00');
INSERT INTO `visits_website` VALUES ('13', 'ip3', 'ip3', '', '2016-08-30 20:30:00');
INSERT INTO `visits_website` VALUES ('14', 'ip4', 'ip4', '', '2016-08-30 20:30:00');
INSERT INTO `visits_website` VALUES ('15', 'ip5', 'ip5', '', '2016-08-30 20:30:00');
INSERT INTO `visits_website` VALUES ('16', 'ip1', 'ip1', '', '2016-08-30 20:30:00');
INSERT INTO `visits_website` VALUES ('17', 'ip2', 'ip2', '', '2016-08-30 20:30:00');
INSERT INTO `visits_website` VALUES ('18', 'ip3', 'ip3', '', '2016-08-30 20:30:00');
INSERT INTO `visits_website` VALUES ('19', 'ip4', 'ip4', '', '2016-08-30 20:30:00');
INSERT INTO `visits_website` VALUES ('20', 'ip5', 'ip5', '', '2016-08-30 20:30:00');
INSERT INTO `visits_website` VALUES ('21', 'ip6', 'ip6', '', '2016-08-29 20:30:00');
INSERT INTO `visits_website` VALUES ('22', 'ip1', 'ip1', '', '2016-08-29 20:30:00');
INSERT INTO `visits_website` VALUES ('23', 'ip2', 'ip2', '', '2016-08-29 20:30:00');
INSERT INTO `visits_website` VALUES ('24', 'ip3', 'ip3', '', '2016-08-29 20:30:00');
INSERT INTO `visits_website` VALUES ('25', 'ip4', 'ip4', '', '2016-08-29 20:30:00');
INSERT INTO `visits_website` VALUES ('26', 'ip5', 'ip5', '', '2016-08-29 20:30:00');
INSERT INTO `visits_website` VALUES ('27', 'ip6', 'ip6', '', '2016-08-29 20:30:00');
INSERT INTO `visits_website` VALUES ('28', 'ip7', 'ip7', '', '2016-08-29 20:30:00');
INSERT INTO `visits_website` VALUES ('29', 'ip1', 'ip1', '', '2016-08-29 20:30:00');
INSERT INTO `visits_website` VALUES ('30', 'ip2', 'ip2', '', '2016-08-29 20:30:00');
Run Code Online (Sandbox Code Playgroud)

我非常感谢你的帮助。

O. *_*nes 5

这是一个很长的问题。关于这种DATETIME基于摘要生成的一个关键建议: 使您的查询可进行查询——使它们能够使用索引。

例如:

 SELECT COUNT(DISTINCT ip)
   FROM visits_website
  WHERE MONTH(create_at) = MONTH(NOW()  /* Slow! */
Run Code Online (Sandbox Code Playgroud)

不是 sargable,因为它将函数 ( MONTH())应用于表中的列。MySQL 必须检查表的每一行以满足此查询。那会很。而是尝试此操作,以查找本月的所有访问。

 SELECT COUNT(DISTINCT ip)
   FROM visits_website
  WHERE create_at >= LAST_DAY(NOW()) + INTERVAL 1 DAY - INTERVAL 1 MONTH
    AND create_at < LAST_DAY(NOW()) + INTERVAL 1 DAY
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为它搜索DATETIME从本月初到但不包括下月初的一系列值。

然后,创建一个复合覆盖索引(create_at, ip)和您的查询应该很好地工作。MySQL 可以扫描它需要的索引范围。

请注意,这也适用于TIMESTAMP数据。