我在Linux下使用MariDB 10.1.18。
我有一个简单的表(t),结构如下:
| id | a | b | c |
-------------------
| 1 | 3 | 7 | 10 |
| 2 | 4 | 6 | 9 |
| 3 | 2 | 7 | 11 |
| 4 | 3 | 5 | 10 |
| 5 | 4 | 8 | 12 |
| 6 | 2 | 9 | 6 |
id is primary key
a - has BTREE index
b - has HASH index
c - has HASH index
我假设主键自动编入索引。 我的查询很简单:
SELECT * FROM t GROUP BY a
出于性能目的,ENGINE USED为MEMORY
。
在500万行上,上述查询需要 1秒来完成并利用一个CPU的线程到100%。现在,第a列约有150个唯一值。
我认为如果我使用松散的索引搜索,这可以解决。不幸的是,这似乎在MariaDB中不起作用,因为它从未使用过。 loosescan将开启。
我试过了
SELECT MAX(a) FROM t GROUP BY a
我的数据库需要1.1秒。
问题是,我怎样才能让这个选择速度快?喜欢0.05秒。
谢谢!
答案 0 :(得分:0)
这取决于你真正想要的东西。你的两个查询都没有多大意义。
SELECT MAX(a) FROM t GROUP BY a
可以改写为
SELECT a FROM t GROUP BY a
或
SELECT DISTINCT a FROM t
并且需要“零”时间。
您的第一个查询将返回每个组的第一行。假设你没有全表索引 - 它将是按id排序的第一行。因此它相当于“查找每组最早的记录”,并且可以重写为
select t.*
from (
select min(id) as id
from t
group by a
) m
join t using(id)
并且也在“没时间”执行。
但像
这样的查询select count(id) as id
from t
group by a
会很慢。与SUM()
和AVG()
相同,因为engin需要读取每一行。虽然MIN()
和MAX()
每组只需要读取一行。
我在InnoDB表上测试了类似的查询,其中包含3.7 M行和30组。
答案 1 :(得分:0)
因此,经过大量的工作和测试,这是迄今为止最快的解决方案:
使用记忆引擎 - 它比存储在RAMDISK上的InnoDB快至少10倍
为每个" a"单独查询列元素而不是使用Group BY并将结果合并到PHP中
防爆。 SELECT id FROM t WHERE b IN(3,4,5)AND c IN(6,7,8)AND a = 1;
为每个列设置复合索引,如INDEX ON(a,b),INDEX ON(a,c),为计划者提供足够的灵活性以适应任何类型的查询。 INDEXES必须是BTREE。
5 mil行表上的一个非常复杂的查询现在大约需要0.35秒。