mySQL - 查询计算行数和总百分比太慢

时间:2017-07-25 14:45:35

标签: mysql sql database database-performance query-performance

表名为'log',目前它有5000万行:

id

我有以下查询,以获取每个'domainIP'使用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 的次数,以及每个'%pck}的百分比:

| 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

它返回:

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`);

结果正是我所需要的,但它无法使用缓慢(需要几分钟)。

这是从phpmyadmin导出的表结构。

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   |

对表格的较小版本的EXPLAIN查询结果:

        if (Directory.Exists(rootFolder))
        {
            try
            {
                string[] valid = { "Test", "OtherTest" };

                foreach (string f in Directory.GetFiles(rootFolder))
                {
                    if (valid.Any(v => f.ToString().Contains(v)))
                    {
                        // create file
                    }
                }
            }
            catch
            {
                // log stuff
            }
        }
    }

我需要制定一个返回相同但可用的查询(以秒为单位返回结果,而不是分钟),但不知道如何

注意:向domainIP添加索引只会略微改善小型样本的响应,但是整个表仍需要10分钟以上才能返回结果。

该表是为其他目的而创建的,如果有的话,我更愿意修改它的结构。

2 个答案:

答案 0 :(得分:2)

你可能会发现这有点快。从这个版本开始:

SELECT l.id, l.domainIP, COUNT(*) as Times,
       (SELECT COUNT(*) FROM log l2 WHERE l2.id = l.id) as Total
FROM log l
GROUP BY l.id, l.domainIP
ORDER BY l.id ASC;

id开头的现有索引应该足够了。

实际上,您甚至可以删除相关子查询来衡量GROUP BY的性能。如果它不够好,那么你基本上知道你无法改进更复杂的查询。您将需要尝试其他方法,例如使用触发器来维持总计数。

答案 1 :(得分:1)

简要地说,查询花费如此巨大的时间并不奇怪,因为varchar非唯一 id varchar < EM> DOMAINIP 。字符串比较可能比在许多数量级上比较int字段要慢。你应该考虑进行非规范化:

  1. id 字段必须为唯一标识符,例如longint;
  2. 您应该声明user_namesid的{​​{1}}表格。然后你应该声明表格&#39; user_ips&#39;由user_nameid(实际上是来自user_id的ID)和user_names组成。
  3. 只有这几项更改必须显着提高查询速度。希望这会对你有所帮助