这是a previous question的后续行动。
如何优化此查询以使其不执行全表扫描?
SELECT Employee.name FROM Employee WHERE Employee.id <> 1000;
explain SELECT Employee.name FROM Employee WHERE Employee.id <> 1000;
+----+-------------+-------------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | Employee | ALL | PRIMARY | NULL | NULL | NULL | 5000 | Using where |
+----+-------------+-------------+------+---------------+------+---------+------+------+-------------+
(Empoyee.id
是主键,如果不清楚的话。)
答案 0 :(得分:4)
有一个名称和id的覆盖索引,它应该能够使用索引来完成查询。这可能会更快,因为整个索引很可能已经在内存中,而表扫描更有可能需要转到磁盘。
由于where子句的选择性较低(不存在),您可能需要提供一个提示以使数据库使用您的索引。我是一个sql服务器人,因此我不确定mysql中提示索引所需的语法,或者即使mysql能够以这种方式利用覆盖索引。
那就是说,我怀疑你可以得到很大改善:你每回一行都会回来。您应该期望需要扫描表格。
答案 1 :(得分:1)
在传统数据库中,你不能!
当然,您可以省略具有给定Id的所有员工(当它是密钥或具有索引时) - 但通常您仍然可以在您的脚下拥有该表的大部分。因此,使用索引可能会使事情变得复杂,因此fts通常是更快的选择。
如果您拥有专门的数据库,则可以存储彼此相邻的所有员工的姓名。
编辑:我现在看到乔尔的另一个答案。是的,这可能是一种方式,因为实际上您的特殊索引现在是存储部分内容的特殊形式。好的数据库可以在覆盖所需的列时使用索引内容 - 这非常好。当然,您将最终进行所谓的“全索引扫描”(但通常比全表扫描更快)。答案 2 :(得分:1)
有很多事情要尝试,这取决于数据库引擎如何选择解析它,真的。一些选择:
select employee.name from employee where employee.id not in (1000);
你也可以尝试使用小于,然后大于。
的联合但是在您给出的具体示例中(对于您的实际案例而言可能过于简单),表扫描不一定是坏事。如果除了一个记录之外必须返回所有记录,那么使用索引实际上可能会更慢。
答案 3 :(得分:1)
你无能为力将提高性能。在这种情况下,数据库必须执行完整的表扫描,因为您要求保存每个记录。读取索引中的每个页面只会降低性能。幸运的是,即使您添加了索引,数据库也足够聪明,可以忽略它......
编辑以解决@Juergens评论 Juergen,你对覆盖指数是正确的,但这里有相互矛盾的影响。在这种情况下使用索引会在某种意义上产生不良影响......查询引擎可能必须为索引中的每个级别执行一次I / O操作,对于它需要检查的每一行。如果索引中有5个级别,那么1M行将是500万次I / O操作,而只有1M个I / O进行完整的表扫描。这就是为什么在这种情况下,大多数查询优化器会忽略任何可用的索引并进行表扫描。 (除非你强制它使用带有提示的索引)唯一的缓解因素是,如果查询所需的每个属性都在索引中(覆盖索引),并且磁盘上每页的索引行数足够小于每页表行,以抵消必须遍历查询返回的每一行索引的每个级别的负面影响。