Клиентский кэш результатов запроса
Рассмотрим ситуацию, когда клиент должен вызывать одни и те же данные через медленное сетевое соединение. Хотя база данных может отправить результаты клиенту из кэша почти немедленно, результат должен еще добраться по проводам к клиенту, что увеличивает общее время выполнения. Существуют специализированные промежуточные оболочки, такие как Oracle Coherence для кэширования данных в Java, PHP и Ruby, но что если бы существовал общий способ кэширования данных на клиентском уровне?
База даных Oracle 11g предоставляет для этих целей клиентский кэш результатов запроса (Client Query Result Cache). Все клиентские стеки базы данных, которые используют драйверы OCI8 (C, C++, JDBC-OCI и так далее), могут использовать эту новую возможность, которая позволяет клиентам кэшировать результаты SQL-запросов локально, а не на сервере. В итоге клиентский кэш результатов запроса предоставляет следующие преимущества:
- Освобождение разработчиков приложений от построения согласованного по процессам (consistent but per-process) кэша результатов SQL, разделяемого всеми сессиями
- Расширение кэширования запроса на сервере до памяти на стороне клиента, путем использования более дешевой клиентской памяти и локального кэширования каждого рабочего набора приложения.
- Увеличение производительности за счет уменьшения обращений к серверу.
- Повышение масштабируемости сервера за счет сбережения его ресурсов.
- Предложение прозрачного управления кэшем: управление памятью, параллельный доступ к наборам результатов и так далее.
- Поддерживаемая прозрачным образом согласованность кэша с изменениями на стороне сервера
- Предложение согласованности в среде RAC
Все, что нужно сделать, чтобы использовать эту возможность – это установить параметр инициализации:
CLIENT_RESULT_CACHE_SIZE = 1G
Этот параметр определяет клиентский кэш размером в 1 Гб, который является суммой кэшей на всех клиентах. (Это статический параметр, поэтому необходимо остановить базу данных, чтобы его установить.) Можно настроить кэши на каждом клиенте, определив другие параметры в файле SQLNET.ORA на стороне клиента:
Параметр
Описание
OCI_RESULT_CACHE_MAX_SIZE |
Определяет размер кэша для этого конкретного клиента |
OCI_RESULT_CACHE_MAX_RSET_SIZE |
Определяет максимальный размер наборов результатов |
OCI_RESULT_CACHE_MAX_RSET_ROWS |
Похож на предыдущий, но определяет количество строк в наборах результатов |
Давайте посмотрим это в действии. Вот простой Java код, который присоединяется к базе данных, используя драйвер OCI8, и выполняет SQL оператор:
select /*+ result_cache */ * from customers.
Подсказка указывает оператору, что необходимо кэшировать результат (другие параметры уже настроены).
import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class CacheTest { private String jdbcURL = "jdbc:oracle:oci8:@PRONE3"; private Connection conn = null; public CacheTest( ) throws ClassNotFoundException { Class.forName("oracle.jdbc.driver.OracleDriver"); } public static void main(String[] args) throws ClassNotFoundException, SQLException { CacheTest check = new CacheTest(); check.dbconnect(); check.doSomething(); } public void dbconnect() throws SQLException { System.out.println("Connecting with URL="+jdbcURL+" as arup/arup"); try { conn = DriverManager.getConnection( jdbcURL, "arup" , "arup"); System.out.println("Connected to Database"); } catch (SQLException sqlEx) { System.out.println(" Error connecting to database : " + sqlEx.toString()); } } public void doSomething() throws SQLException { Statement stmt = null; ResultSet rset = null; try { stmt = conn.createStatement(); System.out.println("Created Statement object"); rset = stmt.executeQuery("select /*+ result_cache */ * from customers"); System.out.println("Retrieved ResultSet object"); if(rset.next()) System.out.println("Result:"+rset.getString(1)); } catch (SQLException sqlEx) { } finally { try { System.out.println("Closing Statment & ResultSet Objects"); if (rset != null) rset.close(); if (stmt != null) stmt.close(); if (conn != null) { System.out.println("Disconnecting..."); conn.close(); System.out.println("Disconnected from Database"); } } catch (Exception e) { } } } }
Сохраните файл как CacheTest.java и затем откомпилируйте код:
$ORACLE_HOME/jdk/bin/javac CacheTest.java
Теперь выполните откомпилированный класс:
$ORACLE_HOME/jdk/bin/java -classpath .:$ORACLE_HOME/jdbc/lib/ojdbc5.jar CacheTest Connecting with URL=jdbc:oracle:oci8:@PRONE3 as arup/ arup Connected to Database Created Statement object Retrieved ResultSet object Result :M Closing Statment & ResultSet Objects Disconnecting... Disconnected from Database
Выполните это несколько раз. После нескольких выполнений можно видеть, что клиент кэшировал значения с помощью динамических представлений, показанных ниже:
select * from client_result_cache_stats$ / select * from v$client_result_cache_stats /
Клиентский кэш результатов запроса очень подходит для справочных таблиц, которые обычно не меняются. (А если они изменятся, кэш обновится.) Он отличается от кэша результатов SQL, который располагается на сервере. Поскольку клиент кэширует результаты, у клиента нет необходимости обращаться к серверу, чтобы получить данные, что не только сберегает пропускную способность, но и циклы ЦПУ на сервере. Более подробную информацию можно найти в Oracle Call Interface Programmers Guide.
Содержание раздела