【发布时间】:2022-11-03 16:35:11
【问题描述】:
我在 laravel 中有这个查询
$visitors = Visitor::select('visitors.sex', 'event_visitor.event_id', DB::raw('count(*) as num_visits'))
->join('event_visitor', 'visitors.id', '=', 'event_visitor.visitor_id')
->whereIn('event_visitor.event_id', $events_id->take(10))
->groupBy('visitors.sex', 'event_visitor.event_id')
->get();
它显示了访问者的性别并在最近 10 次这样的事件中计数
sex event_id num_visits
female 1 10056
male 1 9965
female 2 9894
male 2 9894
现在我的访问者表大小是 600K,事件表是 20,所以每个事件都有 30K 访问者附加,查询需要 2 秒来加载数据
这是 MySQL 形式的查询
select visitors.sex,
event_visitor.event_id,
count(*) as num_visits
from visitors
inner join event_visitor on visitors.id = event_visitor.visitor_id
where event_visitor.event_id in (1,2,3,4,5,6,7,8,9,10)
and visitors.deleted_at is null
group by visitors.sex, event_visitor.event_id
这就是解释所显示的
【问题讨论】:
-
您是否在数据库表中添加了索引?
-
如果您在当前查询前加上
explain前缀,您可以看到 mysql 遵循哪些键。 dev.mysql.com/doc/refman/8.0/en/explain.html -
请您阅读Tips for asking a good Structured Query Language (SQL) question) 并相应地修改您的问题。
-
@GertB。是的,我已经索引了 ID 和性别...
-
看起来你有正确的索引,并且 EXPLAIN 显示它考虑使用
event_id上的索引,但认为它没有提供足够的好处,所以它只使用了表扫描。根据您对每个事件 30K 行的估计,即使使用索引,查询也会检查表中 50% 的行,因此优化器选择不使用它也就不足为奇了。我希望仅当您选择 4 个或更少的事件时它才会使用索引。
标签: mysql sql laravel query-optimization laravel-query-builder