2016-11-04 101 views
-1

我在Linux下使用MariDB 10.1.18。Group By MariaDB非常慢

我有一个简单的表(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秒。

问题是,我该如何让这个选择快速发展?就像0.05秒。

谢谢!

+0

请发布解释结果 – Shadow

+0

需要注意的一点是:只有通过标准开发技术才能实现这一目标。您可能不得不要求DBA配置您的MySQL实例以获得更高的性能。 – Shadow

+0

其目的是过滤掉某些行,然后返回由a分组的最高c行。例如:选择* FROM t WHERE b IN(5,6,7)和IN(2,3)GROUP BY cORT BY c DESC。然而,这不会给出正确的结果,因此连接是必要的。但我不会深究这一点。 – SilviuT

回答

0

所以经过大量的工作和测试,这是迄今为止最快的解决方案:

  1. 使用存储引擎 - 它至少10倍以上的InnoDB快存储在RAMDISK

  2. 制作为每个“a”列元素分别查询,而不是使用Group BY,并将结果组合在PHP
    Ex。 SELECT id FROM t WHERE b IN(3,4,5)and c IN(6,7,8)and a = 1;

  3. 为每个列设置复合索引,例如INDEX ON(a,b),INDEX ON(a,c),以便规划器为任何类型的查询提供足够的灵活性。指标必须是BTREE。

5密耳行表上非常复杂的查询现在需要大约0.35秒。

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()相同。而MIN()MAX()需要每组只读一行。

我在具有3.7 M行和30组的InnoDB表上测试了类似的查询。

+0

其实SELECT DISTINCT a FROM t对于5密耳行需要约0.7秒。 – SilviuT

+0

SELECT a FROM t GROUP BY a - 也需要约0.7秒。 – SilviuT

+0

我已经用30个组测试了一个3.7M行InnoDB表(mysql 5.6.21)上的查询。将副本转换为MyISAM后,一些查询变得非常缓慢。所以试试InnoDB! –