使用索引时的MySQL查询优化

时间:2017-10-02 21:47:28

标签: mysql database indexing database-design

我忙于优化和理解MySQL中的功能。从我从戈登那里学到的答案:

  

select中的所有列都应该是or中的列   使用聚合函数(sum(),avg()等)。

我必须遵循表格和查询

表格

+-----------------+-----------+------------+-------------+
|Id (primary key) | ip(index) | lastattack | create_date |
+-----------------+-----------+------------+-------------+

查询

  SELECT ip,
         lastattack
    FROM blacklist
   WHERE ip = 'xxx.xxx.xxx.xxx'
GROUP BY ip

当我执行上述查询时,我会从 EXPLAIN

收到以下信息
+----+-------------+-------+------+---------------+-----+---------+-----+------+----------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------+---------------+-----+---------+-----+------+----------+-------+
| 1  | SIMPLE      | ipall | ref  | idx           | idx | 257     |const| 2    | 100.00   | Using index condition |
+----+-------------+-------+------+---------------+-----+---------+-----+------+----------+-------+

当我执行查询时,戈登告诉我,我收到以下额外的

  SELECT ip,
         lastattack
    FROM blacklist
   WHERE ip = 'xxx.xxx.xxx.xxx'
GROUP BY ip, lastattack
  

使用索引条件;用在哪里;使用临时;使用filesort

人们告诉我要避免临时或档案。

1 个答案:

答案 0 :(得分:2)

您的查询目前是不正确的 - 或者更确切地说,不明确。假设你有:

192.168.0.1    Attack1    2017-10-01 23:30
192.168.0.1    Attack2    2017-10-01 23:35

应该输出lastattack的哪个值?你没有向服务器提供足够的数据,这些数据无法读懂你的想法,并猜测如果字段被调用" lastattack",你可能想要一个时间戳最大的数据。

这就是Gordon Linoff所说的 - " select中的所有列都应该是GROUP BY中的列,或者使用聚合函数&#34 ;;在这里,lastattack既不是,因为你没有GROUP BY lastattack(但只有IP),你没有聚合它(你选择lastattack,而不是AVG(lastattack)或SOME_AGGREGATE_FUNCTION(lastattack))。

可能仍然可以获得正确的值 - 但您可能不会。在实践中,将以确定的顺序检索记录,并且可能是您想要的顺序。但是其他数据库实现可能会获取它们遇到的第一个值,并让您进行第一次攻击而不是最后一次攻击。

要获得所需的结果,首先需要确定上次攻击的日期:

SELECT ip, MAX(attackdate) AS maxdate FROM blacklist GROUP BY ip;

这为您提供了一个包含正确时间戳的表。要获得最后一次攻击,您需要一个JOIN(如果两次攻击在同一秒内发生,则存在重复攻击,因此您无法确定哪个是最后一次攻击):

SELECT a.ip, a.maxdate, b.lastattack
    FROM (
        SELECT ip, MAX(attackdate) AS maxdate FROM blacklist GROUP BY ip
    ) AS a
JOIN blacklist AS b ON (a.ip = b.ip AND a.maxdate = b.lastattack)

对于内部查询,您需要ipattackdate的索引,这也应该适用于外部查询。您可能希望按此顺序在ipattackdatelastattack上创建索引,以查看是否有任何更改。