我忙于优化和理解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
人们告诉我要避免临时或档案。
答案 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)
对于内部查询,您需要ip
和attackdate
的索引,这也应该适用于外部查询。您可能希望按此顺序在ip
,attackdate
和lastattack
上创建索引,以查看是否有任何更改。