Group By MariaDB 非常慢
Group By MariaDB very slow
我在 Linux 下使用 MariDB 10.1.18。
我有一个简单的 table (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
出于性能目的,使用的引擎是 MEMORY
。
在 500 万行上,上述查询需要 1 秒 完成,并且利用一个 CPU 的线程到 100%。现在 a 列大约有 150 个唯一值。
我认为如果我使用松散索引搜索就可以解决这个问题。不幸的是,这似乎在 MariaDB 中不起作用,因为它从未被使用过。 loosescan 设置为打开。
我试过了
SELECT MAX(a) FROM t GROUP BY a
我的数据库需要 1.1 秒。
问题是,我怎样才能让这个 select 变得非常快?比如0.05秒。
谢谢!
这取决于你真正想要什么。你的两个查询都没有多大意义。
SELECT MAX(a) FROM t GROUP BY a
可以重写为
SELECT a FROM t GROUP BY a
或
SELECT DISTINCT a FROM t
需要 "zero" 时间。
您的第一个查询将 return 每组的第一行。假设您没有 full-table-index - 它将是按 id 排序的第一行。所以相当于"Find the oldest record per group",可以重写为
select t.*
from (
select min(id) as id
from t
group by a
) m
join t using(id)
并且也在"no time"执行。
但是像
这样的查询
select count(id) as id
from t
group by a
会很慢。与 SUM()
和 AVG()
相同,因为引擎需要读取每一行。而 MIN()
和 MAX()
每组只需要读取一行。
我在具有 370 万行和 30 个组的 InnoDB table 上测试了类似的查询。
经过大量工作和测试,这是迄今为止最快的解决方案:
使用内存引擎 - 它比存储在 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) 为计划器提供足够的灵活性来处理任何类型的查询。索引必须是 BTREE。
对 500 万行的非常复杂的查询 table 现在大约需要 0.35 秒。
我在 Linux 下使用 MariDB 10.1.18。
我有一个简单的 table (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
出于性能目的,使用的引擎是 MEMORY
。
在 500 万行上,上述查询需要 1 秒 完成,并且利用一个 CPU 的线程到 100%。现在 a 列大约有 150 个唯一值。
我认为如果我使用松散索引搜索就可以解决这个问题。不幸的是,这似乎在 MariaDB 中不起作用,因为它从未被使用过。 loosescan 设置为打开。
我试过了
SELECT MAX(a) FROM t GROUP BY a
我的数据库需要 1.1 秒。
问题是,我怎样才能让这个 select 变得非常快?比如0.05秒。
谢谢!
这取决于你真正想要什么。你的两个查询都没有多大意义。
SELECT MAX(a) FROM t GROUP BY a
可以重写为
SELECT a FROM t GROUP BY a
或
SELECT DISTINCT a FROM t
需要 "zero" 时间。
您的第一个查询将 return 每组的第一行。假设您没有 full-table-index - 它将是按 id 排序的第一行。所以相当于"Find the oldest record per group",可以重写为
select t.*
from (
select min(id) as id
from t
group by a
) m
join t using(id)
并且也在"no time"执行。
但是像
这样的查询select count(id) as id
from t
group by a
会很慢。与 SUM()
和 AVG()
相同,因为引擎需要读取每一行。而 MIN()
和 MAX()
每组只需要读取一行。
我在具有 370 万行和 30 个组的 InnoDB table 上测试了类似的查询。
经过大量工作和测试,这是迄今为止最快的解决方案:
使用内存引擎 - 它比存储在 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) 为计划器提供足够的灵活性来处理任何类型的查询。索引必须是 BTREE。
对 500 万行的非常复杂的查询 table 现在大约需要 0.35 秒。