我有以下SQL查询:
select expr1, operator, expr2, count(*) as c
from log_keyword_fulltext
group by expr1, operator, expr2
order by c desc limit 2000;
问题:count(*)
作为我的订单的一部分是杀死我的应用程序,可能是因为它不使用索引。我想知道是否有任何方法可以让它更快,例如select
内的另一个select
,或类似的东西。
我的SELECT
解释说:
+----+-------------+----------------------+-------+---------------+-------+---------+------+--------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------------+-------+---------------+-------+---------+------+--------+----------------------------------------------+
| 1 | SIMPLE | log_keyword_fulltext | index | NULL | expr1 | 208 | NULL | 110000 | Using index; Using temporary; Using filesort |
+----+-------------+----------------------+-------+---------------+-------+---------+------+--------+----------------------------------------------+
更新:
我试着做那样的子查询
select * from (select b.expr1,b.operator,b.expr2,count(*) as c
from log_keyword_fulltext b group by b.expr1,b.operator,b.expr2) x
order by x.c desc limit 2000;
它的工作但不是更快,以下是解释:
+----+-------------+------------+-------+---------------+-------+---------+------+--------+----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+-------+---------------+-------+---------+------+--------+----------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 38398 | Using filesort |
| 2 | DERIVED | b | index | NULL | expr1 | 208 | NULL | 110000 | Using index |
+----+-------------+------------+-------+---------------+-------+---------+------+--------+----------------+
你现在可以检查它,它不再使用临时,但它仍然具有相同的性能。任何建议?
答案 0 :(得分:2)
您正在运行需要扫描整个表的查询,这不会扩展。没有WHERE子句,因此绝对需要扫描整个事物。
考虑维护一些摘要表,而不是经常进行此查询。
答案 1 :(得分:1)
总是尝试计算一些单列而不是计数(*),因为它需要计算每行每列的permutaiotion。所以需要更长的时间
Eg:
select expr1, operator, expr2, count(expr1) as c
from log_keyword_fulltext
group by expr1, operator, expr2
order by c desc limit 2000;
答案 2 :(得分:1)
我错过了什么?我没有看到WHERE子句。在我看来,您请求进行表格扫描。
如果你指望你的“LIMIT”条款,那你就不幸了 - 这就是COUNT汇总计算。
答案 3 :(得分:0)
“杀死你的申请”是什么意思?背景是什么?您多久运行一次此查询?运行此查询时数据库上发生了什么?这个特定的结果是否必须是实时的?有什么条件(insert / s,选择/ s,db大小等)
以下是您可以做的事情:
将计数存储在一个单独的表中,您可以在插入/删除时使用触发器更新
如果你不能通过一个简单的表格滑动强制MySQL进行这种操作,请尝试使用存储过程执行类似(伪代码)的操作:
CREATE TEMP TABLE t (e1 EXP_T, op OP_T, e2 EXP_T, count INTEGER)
ADD AN INDEX ON count
FOR EACH LINE OF SELECT exp1,operator,exp2 FROM log_blah DO
UPDATE t SET count=count+1 WHERE exp1=e1 AND operator=op AND exp2=e2
IF IT DOES NOT WORK INSERT INTO t VALUES (exp1,operator,exp2,1)
DONE
SELECT * FROM t ORDER BY count DESC LIMIT 2000
1可能就是你想要的。并忘记索引,这个查询无论如何都要刷整个表。
答案 4 :(得分:0)
防止表扫描的最佳方法是为您经常访问的字段添加封面索引。创建索引需要一次性成本。对表上的INSERT和DELETE操作还有一些额外的成本,因此可以更新索引。
封面索引可防止数据库必须将整个记录读入内存,以便访问您关心的少数字段的值。整个查询可以在索引上运行。
ALTER TABLE `log_keyword_fulltext` ADD INDEX `idx_name`(expr1, operator, expr2)
如果这些不是实际字段,而是字段上的操作,例如left(foo,20),您实际上可以索引将在SELECT或WHERE子句中使用的字段部分。
有关其他优化提示,请参阅this page。
答案 5 :(得分:-1)
试图计算和排序它将是一个杀手。我建议尝试用计数制作一个临时表,然后选择...按顺序排列。
不确定这是否适用于MySQL,但是在PostreSQL或Oracle中,这将是
create foo as
select expr1, operator, expr2, count(*) as c
from log_keyword_fulltext
group by expr1, operator, expr2;
select * from foo order by c desc limit 2000;
此外,为了对它们进行排序,您将不得不进行所有计数,因此限制条款不会阻止它进行所有这些计算。