我有一个超过2500万行的MySQL表。因此,为了避免破坏整个数据库,我不想进行任何查询,这些查询会导致在磁盘上创建临时表,例如对未索引列的排序。
因此,如果表具有以下列...
employee_id
first_name
last_name
hire_date
manager_id
假设我想看到有3名或3名以上员工为他们工作的经理,就像这样(假设manager_id没有索引)。
select count(*), manager_id from employee group by manager_id having count(id) > 3
如果我将结果集限制为仅适用于2016年之后雇用的那些雇员,这将有助于此查询的性能。
select count(*), manager_id from employee where hire_date > ‘2016-01-01’
group by manager_id having count(id) > 3
让我们假设hire_date也没有索引。额外的where子句会有所帮助吗?
答案 0 :(得分:2)
是的,限制WHERE
子句中的行意味着要分组的行将更少,并且某些组甚至不会显示,因为该组中的行已经被过滤掉了。 / p>
GROUP BY
可能会在您的查询中创建一个临时表。但是至少它将有一个较小的临时表,因为将有较少的组。避免使用临时表的方法是按manager_id
上的索引以索引顺序进行查询扫描。
如果MySQL可以确定可以按manager_id
进行扫描,则可以避免使用temp表,因此假定连续扫描每个组,它可以更轻松地计算每个组中的行。换句话说,当它到达给定manager_id
的最后一行时,它知道该相同的manager_id
不会再有更多行了。因此,不需要对每个manager_id的计数进行计数。完成扫描每组行后,它只能输出每个manager_id的每个计数。
但是您可能会发现hire_date
上的索引具有更大的优势。如果这种情况可以通过从hire_date > '2016-01-01'
的行开始避免扫描大部分表,那么临时表的开销可能小于表扫描的开销。
无法进行通过manager_id
上的索引扫描和也通过hire_date
上的索引扫描的查询。哪种策略更好,取决于表中有多少行匹配不同的条件。
答案 1 :(得分:0)
我认为,如果由于where子句而导致数据量显着减少,那肯定会有所帮助。
尽管没有其他选择可以自己尝试。
答案 2 :(得分:0)
愚蠢。
我可以为您显示10行表和一个查询(使用JOIN
,但不使用GROUP BY
),这将占用磁盘上的TB临时空间。
我的意思是,没有简单的方法可以防止流氓查询“使系统崩溃”。
在您的“雇用日期”修复程序中,如果经理在2016年之前有2名员工,而在之后有2名员工,该怎么办?您的“改进”查询将找不到他们的经理。
具有INDEX(manager_id)
会使有些有所不同,但仍然会有“全索引扫描”,仅比“全表扫描”好一点。
添加hire_date子句不一定有帮助。特别地,INDEX(hire_date)
不可能完全帮助 。甚至INDEX(hire_date, manager_id)
(但不是其他顺序)也可以帮助一些。
那只是对该相对简单查询的部分分析。那其他查询呢?愚蠢的。
一件事会有所帮助:使用InnoDB,而不是MyISAM。