`

行预取研究

阅读更多

1.行预取         

      在应用程序从数据库读取数据的时候,它可以一条一条地读取,也可以更好一点,一次读取多条记录。一次读取多条记录被称为行预取.

 1.1运行机制

      每次应用程序请求驱动从数据库返回1条记录的时候,会预取多条记录并将它们存储在客户端的内存中。这样,多个后续的请求就不需要执行数据库调用来读取数据。可以直接从客户端内存中得到它们。结果,到数据库的往返次数随预取记录数量的增加呈比例地降低。因此,检索包含大量记录的结果集的开销会显著降低。

      必须明白的是,在没有行预取的情况下,检索性能之所以差并不是数据库引擎造成的。而是应用程序导致了低性能,返回来又被低性能拖累。

      尽管行预取功能对客户端来讲更加重要,数据库也能从中得到好处。事实上,行预取功能显著地降低了逻辑读的次数。

     下面演示在PL/SQL、JDBC以及ODP.NET环境下有效地使用行预取功能。

  1。PL/SQL

      如果在编译的时候动态初始化参数plsql_optimize_level被设置成2或者2以上,就会针对基于游标的FOR循环使用行预取功能。

  ALTER SESSION SET plsql_optimize_level = 2;

BEGIN
  FOR c IN (SELECT * FROM t)
  LOOP
    -- process data
    NULL;
  END LOOP;
END;

   必须强调的是,行预取功能只能自动地应用到基于游标的FOR循环中。要对其他类型的游标使用行预取功能,必须使用BULK COLLECT 子句。下面是一个使用它来操作隐式游标的例子。

 

DECLARE
  TYPE t_t IS TABLE OF t%ROWTYPE;
  l_t t_t;
BEGIN
  SELECT * BULK COLLECT INTO l_t
  FROM t;
  FOR i IN l_t.FIRST..l_t.LAST
  LOOP
    -- process data
    NULL;
  END LOOP;
END;

     在前面的PL/SQL匿名块中,结果集中的所有记录都是在一次读取中返回的。如果记录数量很大,会需要使用大量的内存来保存它。因此,在实际操作中,要么知道要返回的记录数是有限的,要么需要使用LIMIT子句为每次读取设置一个范围。示例如下:

 

DECLARE
  CURSOR c IS SELECT * FROM t;
  TYPE t_t IS TABLE OF t%ROWTYPE;
  l_t t_t;
BEGIN
  OPEN c;
  LOOP
    FETCH c BULK COLLECT INTO l_t LIMIT 100;
    EXIT WHEN l_t.COUNT = 0;
    FOR i IN l_t.FIRST..l_t.LAST
    LOOP
      -- process data
      NULL;
    END LOOP;
  END LOOP;
  CLOSE c;
END;

    包dbms_sql、本地动态SQL和RETURNING子句都支持行预取功能。

 2.JDBC

          Oracle JDBC驱动默认启用了行预取功能。可以用两种方式来改变默认的预取记录的数量。第一种是在使用类OracleDataSource或OracleDriver创建数据库的连接时指定属性defaultRowPrefetch。示例如下:

 

 connectionProperties = new Properties();

 connectionProperties.put("user",user);

 connectionProperties.put("password",password);

 connectionProperties.put("defaultRowPrefetch","100");

 dataSource.setConnectionProperties(connectionProperties );

 

第二种方法是在Staement类中使用方法setFetchSize来覆盖连接级别的默认值。示例如下:

 

      sql = "SELECT id, pad FROM t";
      statement = connection.prepareStatement(sql);
      statement.setFetchSize(100);
      resultset = statement.executeQuery();
      while (resultset.next())
      {
        id = resultset.getLong("id");
        pad = resultset.getString("pad");
        // process data
      }
      resultset.close();
      statement.close();

 

   3.ODP.NET

     ODP.NET定义的默认读取大小(65536)是字节数而不是记录数。可以通过类OracleCommand和OrcleDataReader提供的属性FetchSize来改变它的大小。示例如下:

 

           String sql;
            OracleCommand command;
            OracleDataReader reader;
            Decimal id;
            String pad;

            sql = "SELECT id, pad FROM t";
            command = new OracleCommand(sql, connection);
            command.AddToStatementCache = false;
            reader = command.ExecuteReader();
            reader.FetchSize = command.RowSize * fetchSize;
            while (reader.Read())
            {
                id = reader.GetDecimal(0);
                pad = reader.GetString(1);
                // process data
                // Console.WriteLine(id + " , " + pad);
            }
            reader.Close();

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics