如何快速检查数据库表中的记录?

10

我需要处理一张非常大的表。我想检查是否存在某些记录的parent_id等于我传递的值。 目前,我使用的方法是使用"select count(*) from mytable where parent_id = :id",如果结果> 0,则意味着它们存在。

因为这是一个非常大的表,而且我不在乎存在确切数量的记录,我只想知道它是否存在,所以我认为count(*)效率有点低。

如何以最快的方式实现此要求? 我正在使用Oracle 10。

#

根据hibernate Tips&Tricks https://www.hibernate.org/118.html#A2

建议像这样编写:

Integer count = (Integer) session.createQuery("select count(*) from ....").uniqueResult();

我不知道uniqueResult()的魔力在哪里? 它为什么会快?

与"select 1 from mytable where parent_id = passingId and rowrum < 2 "相比,哪个更有效?

6个回答

11

如果你对记录数量不感兴趣,那么使用 EXISTS 查询是一个好选择:

select 'Y' from dual where exists (select 1 from mytable where parent_id = :id)

如果记录存在,这将返回“Y”,否则不会返回任何内容。

[就Hibernate中的“uniqueResult”而言,它只返回一个对象(当只有一个对象要返回时),而不是包含1个对象的集合。如果返回多个结果,则该方法会抛出异常。]


你甚至不需要查询DUAL表 - select 'Y' from mytable where parent_id = :id AND ROWNUM = 1 可以得到相同的结果。 - Jeffrey Kemp
1
是的 - 我只是不喜欢"ROWNUM = 1" - 感觉不如EXISTS查询透明。只是我的个人看法。 - Nick Pierpoint

5

以下两者没有实质区别:

select 'y' 
  from dual 
 where exists (select 1 
                 from child_table 
                where parent_key = :somevalue)

并且。
select 'y' 
  from mytable 
 where parent_key = :somevalue 
   and rownum = 1;

至少从Oracle10gR2开始,以下内容都是适用的。在这个版本中,Oracle足够聪明,可以执行一个FAST DUAL操作,其中它会将任何真正的活动归零。如果以后需要考虑移植,则第二个查询更容易移植。

真正的性能差异取决于parent_key列是否被索引。如果没有被索引,那么你应该运行类似以下的内容:

select 'y' 
  from dual 
 where exists (select 1 
                 from parent_able 
                where parent_key = :somevalue)

5

如果你有索引,使用select count(*)应该非常快速。如果没有索引,允许数据库在第一个匹配后中止也不会有太大帮助。

但既然你问了:

boolean exists = session.createQuery("select parent_id from Entity where parent_id=?")
                        .setParameter(...)
                        .setMaxResults(1)
                        .uniqueResult() 
                 != null;

由于我没有hibernate来测试,一些语法错误是可以预见的。

对于Oracle数据库,hibernate将maxResults翻译成rownum。

至于uniqueResult()的作用,请阅读其JavaDoc!使用uniqueResult而不是list()不会影响性能;如果我记得正确,uniqueResult的实现委托给了list()。


2

首先,您需要在mytable.parent_id上创建索引。

这应该足以使您的查询足够快,即使对于大型表格(除非还有许多具有相同parent_id的行)。

如果不是这样,您可以编写

select 1 from mytable where parent_id = :id and rownum < 2

该语句将返回包含1个行或者不返回任何行的结果。它不需要计算行数,只需找到一个符合条件的行并停止查询。但这是Oracle特有的SQL语法(因为rownum),建议不要使用。


2
我认为我会选择一个EXISTS查询 - 更透明地满足要求:select 1 from dual where exists (select 1 from mytable where parent_id = :id) - Nick Pierpoint

0

如果存在任何记录,则此查询将返回1,否则返回0:

SELECT COUNT(1) FROM (SELECT 1 FROM mytable WHERE ROWNUM < 2);

当您需要检查表格数据统计信息时,它可以帮助您,而不管表格大小和任何性能问题。


0

对于DB2,有类似于select * from mytable where parent_id = ? fetch first 1 row only的语句。我认为Oracle也有类似的语句。


1
所有的SQL方言都不同 - 你不能假设有相似的东西,例如Oracle有rownum,而在Sybase和DB2中没有。 - mmmmmm
2
所以,rownum的概念是我所谓的“类似”,因为它涵盖了相同的用例,即获取前n条记录(http://www.petefreitag.com/item/59.cfm)。 - bertolami
关于 top n 的问题。使用 rownum 的一个问题是它在排序之前被计算,所以它并不真正代表“top” n。 - Thilo
1
但由于排序在这里并不重要,我认为没有理由给这个答案点踩。虽然它没有给出正确的答案,但它指向了正确的方向,因此是有帮助的。因此,+1。 - meriton
1
不偏袒任何一方,但对于一个明确标注为“Oracle”的问题,我会期望只使用Oracle语法。在我看来。 - Jeffrey Kemp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接