我已经调试了好几个小时,非常感谢您提供帮助,以查看是否遗漏了非常明显的内容。我有一个具有30k行的MySQL表。架构如下:
CREATE TABLE `log` (
`ip` varchar(15) COLLATE utf8mb4_unicode_520_ci NOT NULL,
`date` int(11) NOT NULL,
`requested` mediumtext COLLATE utf8mb4_unicode_520_ci NOT NULL,
`response` mediumtext COLLATE utf8mb4_unicode_520_ci NOT NULL,
`id` bigint(20) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci;
索引是:
ALTER TABLE `logs`
ADD PRIMARY KEY (`id`) USING BTREE,
ADD KEY `date` (`date`);
在phpmyadmin中,当我查询SELECT ip, date, requested FROM log ORDER BY date DESC LIMIT 0, 1000
时,查询需要花费几毫秒。但是,在我的PHP代码中,当我执行相同的查询时:
$mysqli = new mysqli(...);
$s = microtime(true);
$mysqli->set_charset('utf8mb4');
$query = $mysqli->prepare('SELECT ip, date, requested FROM log ORDER BY date DESC LIMIT 0, 1000');
$query->execute();
$query->bind_result($ip, $date, $requested);
while($query->fetch()) {
// ... just echoing the results
}
$e = microtime(true);
echo $e - $s;
需要6到7秒。列id
是主键,索引设置为PRIMARY
和date
。
一些观察和调试步骤:
如果我移除set_charset
,则需要1.5秒。
如果我保留utf8mb4
字符集,但仅选择ip
和date
,查询将在〜0.002秒内完成。
我在网上搜索解决方案,例如this solution没有任何区别。
EXPLAIN
表示possible_keys
是null
,这很奇怪,因为似乎date
应该用作索引。即使FORCE INDEX
也不使用索引。
在我将排序规则更改为utf8mb4_unicode_520_ci
之前,它工作得很好-以前是utf8_unicode。
我想念的是什么?我如何才能将此查询加速到合理的水平?提前非常感谢您!! :)
SELECT ip, date, requested FROM log
ORDER BY date DESC LIMIT 0, 1000
需要INDEX(date)
。
如果要从一个ip
中获取最新的20个,
SELECT ip, date, requested FROM log
WHERE ip = '11.22.33.44'
ORDER BY date DESC LIMIT 0, 20
需要INDEX(IP, date)
。
如果ip
是IP地址,则ascii
就足够了。这只会比utf8mb4
快一点。字符集是导致速度下降的原因。缺少索引是。速度下降的另一个原因是铲起1000个笨重的(?)行。
A
可能
速度下降和时序变化较大的原因是innodb_buffer_pool_size
的值。buffer_pool太小而无法保存数据;它会击中磁盘。你有多少RAM?应将buffer_pool_size设置为available RAM的大约70%。为什么date
是INT
?请参见数据类型DATETIME
,DATE
,TIMESTAMP
。请提供EXPLAIN
;您说的某些话彼此不同。并执行EXPLAIN FORMAT=JSON SELECT ...
了解更多信息。 (如果该格式不可用,那么该升级您的MySQL版本了。)
您是否忽略IPv6的存在?