【发布时间】:2017-07-25 14:45:35
【问题描述】:
名为“log”的表,目前有 5000 万行:
| id | domainIP |
| foo | 158.132.34.5 |
| bob | 128.12.244.3 |
| bob | 128.12.244.3 |
| bob | 19.152.134.4 |
| bob | 168.152.34.9 |
| alice | 178.132.64.10 |
| alice | 188.152.214.200 |
| peter | 208.162.36.153 |
| peter | 208.162.36.153 |
| peter | 208.162.36.153 |
| peter | 198.168.94.201 |
我有以下查询,以获取id 与每个“域IP”一起使用的次数,以及每个“域IP”的百分比:
SELECT
`log`.`id`,
`log`.`domainIP`,
COUNT(`log`.`domainIP`) AS "Times",
totalsTable.Totals,
(COUNT(`log`.`domainIP`)/totalsTable.Totals)*100 AS "Percentage"
FROM `log`
JOIN
(
SELECT
`id`,
COUNT(`domainIP`) AS Totals
FROM `log` GROUP BY `id`
) AS totalsTable
ON (`log`.`id` = totalsTable.`id`)
GROUP BY `log`.`domainIP` ORDER BY `log`.`id` ASC, "Percentage" DESC
返回:
| id | domainIP | Times | Totals | Percentage
| foo | 158.132.34.5 | 1 | 1 | 100
| bob | 128.12.244.3 | 2 | 4 | 50
| bob | 19.152.134.4 | 1 | 4 | 25
| bob | 168.152.34.9 | 1 | 4 | 25
| alice | 178.132.64.10 | 1 | 2 | 50
| alice | 188.152.214.200 | 1 | 2 | 50
| peter | 208.162.36.153 | 3 | 4 | 75
| peter | 198.168.94.201 | 1 | 4 | 25
结果正是我需要的,但速度太慢了(需要几分钟)。
这是从 phpmyadmin 导出的表结构。
CREATE TABLE `log` (
`id` varchar(150) COLLATE utf8_unicode_ci DEFAULT NULL,
`eDate` datetime DEFAULT NULL,
`domainIP` varchar(150) COLLATE utf8_unicode_ci DEFAULT NULL,
`event` varchar(150) COLLATE utf8_unicode_ci DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
ALTER TABLE `log`
ADD UNIQUE KEY `logUnique` (`id`,`eDate`,`event`),
ADD KEY `eDate` (`eDate`),
ADD KEY `id` (`id`,`eDate`),
ADD KEY `event` (`id`,`eDate`,`event`);
对较小版本的表进行 EXPLAIN 查询的结果:
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra
1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 100 | Using where; Using temporary; Using filesort
1 | PRIMARY | log | ref | logUnique,id,event | logUnique | 453 | totalsTable.id | 1 |
2 | DERIVED | log | index | NULL | id | 459 | NULL | 100 |
我需要制定一个返回相同但可用的查询(以秒而不是分钟的方式返回结果),但不知道如何
注意:给 domainIP 添加索引只会稍微改善小样本的响应,但完整的表仍然需要 10 多分钟才能返回结果。
该表是为其他目的而创建的,我更愿意尽可能少地修改它的结构。
【问题讨论】:
-
暂且不说表的设计非常糟糕,你可以做的是让你的 MySQL 使用更多的内存——这是通过使用
InnoDB作为存储引擎并增加@987654328 的值来完成的@ 系统变量。由于您使用的是 PHPMyAdmin,并且由于您的表的结构非常相似,因此我猜测您正在运行默认设置,因此 MySQL 可以在超级旧的硬件上运行。现在,至于为什么 table 的设计很糟糕 - 它并不真正相关,您要做的是将 I/O 从磁盘转移到 RAM,从而增加该 var 的值。 -
@Mjh 我会看看那个。本来这个表是为了一个完全不同的目的而设计的,很多年前,这是我现在才需要添加的一个功能,我不打算为了这么小的新需求重新设计这样的表。
-
我了解您来自哪里,我们都曾遇到过这样的问题。无论如何,您要做的是将硬盘的缓慢性排除在外,并依靠 RAM 的读取 I/O 为 CPU 提供信息。实际的工作量将是相同的,不同之处在于计算机将从更快的存储中读取。通常,这就是 MySQL 和错误查询的魔锤。确保不要过度使用
innodb_buffer_pool_value。 -
键
id和event与logunique是多余的;放下那两个。将UNIQUE logunique提升为PRIMARY KEY。
标签: mysql sql database database-performance query-performance