【问题标题】:The fastest way to check if some records in a database table?检查数据库表中是否有某些记录的最快方法?
【发布时间】:2010-01-25 09:03:42
【问题描述】:

我有一张大桌子可以使用。我想检查是否有一些记录的 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

【问题讨论】:

    标签: database oracle hibernate


    【解决方案1】:

    如果您对记录数不感兴趣,可以使用 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 给出相同的结果。
    • 是的——只是不喜欢“ROWNUM = 1”——感觉不像 EXISTS 查询那样透明。不过只有我。
    【解决方案2】:

    如果你有一个索引,select count(*) 应该会很快,如果你没有,让数据库在第一次匹配后中止不会有多大帮助。

    但是既然你问了:

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

    (可能会出现一些语法错误,因为我没有在这台计算机上测试休眠)

    对于 Oracle,maxResults 由 hibernate 转换为 rownum。

    关于 uniqueResult() 的作用,请阅读它的 JavaDoc!使用 uniqueResult 而不是 list() 对性能没有影响;如果我没记错的话,uniqueResult 的实现委托给 list()。

    【讨论】:

      【解决方案3】:

      两者之间没有真正的区别:

      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)
      

      【讨论】:

        【解决方案4】:

        首先,您需要一个 mytable.parent_id 上的索引。

        这应该使您的查询足够快,即使对于大表也是如此(除非还有很多行具有相同的 parent_id)。

        如果没有,你可以写

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

        这将返回包含 1 的单行,或者根本没有行。它不需要计算行数,只需找到一个然后退出。但这是特定于 Oracle 的 SQL(因为 rownum),您不应该这样做。

        【讨论】:

        • 我认为我会进行 EXISTS 查询 - 对要求更透明:select 1 from dual where exists (select 1 from mytable where parent_id = :id)
        【解决方案5】:

        对于 DB2,有类似 select * from mytable where parent_id = ? fetch first 1 row only 的内容。我假设 oracle 存在类似的东西。

        【讨论】:

        • 所有 SQl 方言都不同 - 你不能假设有类似的东西,例如Oracle 的 rownum 在 Sybase 中没有,我认为在 DB2 中
        • 所以 rownum 概念就是我所说的“相似”,因为它涵盖了相同的用例,即获取前 n 条记录 (petefreitag.com/item/59.cfm)
        • 回复:前 n 个。 rownum 的一个问题是它在任何排序完成之前被评估,所以它不是真正的“顶部”n。
        • 但是由于排序在这里无关紧要,我认为这个答案没有理由值得反对。虽然它没有给出正确的答案,但它指向了正确的方向,因此很有帮助。因此,+1。
        • 不投票,但对于一个明确表示“Oracle”的问题,我只希望使用 Oracle 语法。恕我直言。
        【解决方案6】:

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

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

        当您需要检查表数据统计信息时,它会有所帮助,无论表大小和任何性能问题。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2023-03-18
          • 2016-12-10
          • 1970-01-01
          • 2019-07-31
          • 1970-01-01
          • 1970-01-01
          • 2021-10-23
          • 1970-01-01
          相关资源
          最近更新 更多