是否可以优化使用'<>'的查询运营商?

时间:2009-07-28 20:37:02

标签: mysql performance indexing

这是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是主键,如果不清楚的话。)

4 个答案:

答案 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进行完整的表扫描。这就是为什么在这种情况下,大多数查询优化器会忽略任何可用的索引并进行表扫描。 (除非你强制它使用带有提示的索引)唯一的缓解因素是,如果查询所需的每个属性都在索引中(覆盖索引),并且磁盘上每页的索引行数足够小于每页表行,以抵消必须遍历查询返回的每一行索引的每个级别的负面影响。