我有一个大约50GB大小的MYSQL数据库,有数百万行。这是我的表结构
CREATE TABLE `logs` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`mac` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`firstTime` datetime DEFAULT NULL,
`lastTime` datetime DEFAULT NULL,
`locid` int(11) DEFAULT NULL,
`client_id` int(11) DEFAULT NULL,
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL,
`isOut` tinyint(1) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `index_logs_on_location_id` (`location_id`),
KEY `index_logs_on_client_id` (`client_id`),
KEY `macID` (`macID`)
) ENGINE=InnoDB AUTO_INCREMENT=39537721 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
我正在寻找避免全表扫描的方法。我试图为mac列添加索引。但是当我在查询上运行EXPLAIN
时,当我在client_id
子句中不使用WHERE
时,possible_keys和键总是NULL,否则我唯一使用的索引是client_id或location_id在执行时间方面,我的查询没有显着影响。我主要使用这些类型的查询(分组,排序等)。
SELECT mac,COUNT(mac),DATE(lastTime)
FROM logs
WHERE client_id = 1
GROUP BY mac,DATE(lastTime)
当您考虑这种类型的表结构时,如何优化表以更快地执行查询?我对所有建议持开放态度。谢谢
答案 0 :(得分:1)
让MySQL(或Oracle,SQL Server,Postgres,MariaDB,DB2等)使用索引取决于 mac 列中数据的唯一性以及唯一性的分布是。提到的数据库引擎使用基于成本的优化器,该优化器估计某个解决方案的成本并以最低的成本执行解决方案。有时他们是不正确的。使用数据库参数可以影响此估计值,但这可能会对其他查询产生意外的副作用。
影响结果的第二种方法是更改数据结构。
第三种方式,最可行的是通过提供提示来影响执行计划。为此,假设mac
和lastTime
上存在索引,以便db引擎只需加载此索引即可完成其工作:
CREATE INDEX idx_mac_nn_1 ON logs(mac,lastTime);
假定为优化查询(因此您的版本没有client_id
列)
SELECT mac,COUNT(mac),DATE(lastTime)
FROM logs FORCE INDEX idx_mac_nn_1
GROUP BY mac,DATE(lastTime);
然后应该强制MySQL使用索引,无论如何。
答案 1 :(得分:0)
对于此查询:
SELECT mac, COUNT(mac), DATE(lastTime)
FROM logs
WHERE client_id = 1
GROUP BY mac, DATE(lastTime)
您需要(client_id, mac, lastTime)
上的索引。如果你不介意所需的额外空间,我会建议一个覆盖索引。