[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference orarep::nomahs::sql_services

Title:SQL/Services Forum
Notice:kits(3) ft info(7) QAR access (8) SPR access (10)
Moderator:SQLSRV::MAVRIS
Created:Thu Oct 13 1988
Last Modified:Fri Jun 06 1997
Last Successful Update:Fri Jun 06 1997
Number of topics:2214
Total number of notes:8586

2165.0. "SQLSRV API questions -- thanks!" by ORAREP::VSSCAD::FITZGERALD () Thu Mar 13 1997 20:11

Hi,

I am operating on a VAX 6000-550, with the following RDB/SQL/SQLSRV versions:
DEC SQL VERSION,         value: V6.1-01
RDB ENG VERSION,         value: V6.1-01
SERVER PROTOCOL VERSION, value: 8
SQLSRV SRV VERSION,      value: V6.1-01

I have written a SQLSRV routine which retrieves information via a 
database class server defined as follows:

CLASS   "RDB_DB_V2"
STARTUP "SQLSRV$SRV"
USER    "RDBUSER"
EXECUTE "ATTACH 'FILENAME DBDISK:[RDBDIR.DB]RDB_DB'"
IDENT   "RDB_READ"
MIN     5
MAX     20
IDLE    1800

This code only needs to handle "select" commands, and calls out the 
following SQL Services API routines:
 sqlsrv_associate
 sqlsrv_prepare
 sqlsrv_allocate_sqlda_data
 sqlsrv_declare_cursor -- SQLSRV_TABLE_CURSOR/SQLSRV_MODE_READ_ONLY
 sqlsrv_open_cursor
 sqlsrv_fetch_many
 sqlsrv_fetch
 sqlsrv_close_cursor
 sqlsrv_release_statement

This code is reentrant, never dies unless we kill it, and is called via a 
UCX socket connection.  Our UCX version is: DEC TCP/IP Services for 
OpenVMS VAX Version 3.1.

The first version of the code ALWAYS called sqlsrv_associate and ALWAYS
RELEASED that connection with sqlsrv_release.  This caused a performance
problem as it took approx 7 seconds to return the resultant query.  The
latest release establishes a connection with the database class server 
the first time the image is accessed, and NEVER releases via sqlsrv_release,
however it does always call sqlsrv_release_statement.
This had an incredibly positive impact on our retrieval time.

A couple of questions:

- a separate update process has been having problems with intermittent locking
  with this approach, and we are suspicious of this implementation since killing
  the pid associated with this process appears to allow the update to happen.
  this is curious, since the cursor is defined as "SQLSRV_TABLE_CURSOR/
  SQLSRV_MODE_READ_ONLY".

- any problems with this approach given that updates are attempting to occur
  while this image is running, and never exits unless we kill it?

- any other performance improving techniques/stategies available especially
  in the database class configuration defined above?

I'd really appreciate any/all feedback.  I am working off of old v5.1
bookreader documentation, and funding won't permit spending in this area.

Thanks very much,
Patti
T.RTitleUserPersonal
Name
DateLines
2165.1Use explicit read only transactions.ORAREP::HERON::GODFRINDOracle Rdb EngineeringFri Mar 14 1997 05:2947
>- a separate update process has been having problems with intermittent locking
>  with this approach, and we are suspicious of this implementation since killing
>  the pid associated with this process appears to allow the update to happen.
>  this is curious, since the cursor is defined as "SQLSRV_TABLE_CURSOR/
>  SQLSRV_MODE_READ_ONLY".

On what sort of locks does the locking occur ? (the "stall messages" screen of
RMU/SHOW STAT will show that). Probably a table or record lock. 

The "read only" cursor mode only indicates that the program is not allowed to
do any updates via that cursor. It has no impact on the sort of locking done by
the database. To get true read only behaviour, you should start a read-only
transaction and commit it once you are done with the query. Otherwise, the SQL
default is to start a read-write transaction. In this mode, all the rows (and
index nodes) your query will touch will be read-locked until the end of the
transaction, preventing any other program from updating those records or index
nodes.

Also, you can go one step further in improving the performance of your program. 
If the same query is executed each time, then you need to prepare it only once.
Make sure all variable information is passed via host variables instead of
litterals in the SQL text. 

 sqlsrv_associate
 sqlsrv_prepare
 sqlsrv_allocate_sqlda_data
 sqlsrv_declare_cursor -- SQLSRV_TABLE_CURSOR/SQLSRV_MODE_READ_ONLY
 repeat as necessary
   sqlsrv_execute_immediate (to start a read only transaction)
   sqlsrv_open_cursor
   repeat as necessary
     sqlsrv_fetch_many
     sqlsrv_fetch
   sqlsrv_close_cursor
   sqlsrv_execute_immediate (to commit the read only transaction)
 sqlsrv_release_statement
 sqlsrv_release

If you have multiple statements, you can keep them all prepared the same way.
Just make sure to remember the statement ids, SQLDAs and cursor ids for each
statement. 

Finally, since you are (cleverly) using the fetch_many mechanism, make sure to
use as large as possible a buffer. Not sure what the maximum buffer size is for
5.1 though.

/albert
2165.2thanks ?persistent connection a prob?ORAREP::VSSCAD::FITZGERALDFri Mar 14 1997 15:2821
Hi,

Thanks so much for the response. 

I am in the process of modifying the code to "set transaction read only"
to guarantee the transaction state.  Thanks for making that suggestion.

Although the code deals with "select" statements, with the exception of 
the "set transaction", the selects are different (eg. search for different
values, and even different tables).  I'm assuming that I must continue to 
prepare these statements as well.

Our most important concern is the connection space.  Is there a problem in
establishing a single connection that persists as long as the vax/vms 
node continues to operate?  Will the integrity of the data be compromised
given the update process mentioned in my base note (eg. if a row is 
modified by the update process and my program is constantly accessed via
UCX, will that changed row be available to my program?)

Thanks again VERY much Albert for your help,
Patti
2165.3ORAREP::HERON::GODFRINDOracle Rdb EngineeringMon Mar 17 1997 10:2571
>Although the code deals with "select" statements, with the exception of 
>the "set transaction", the selects are different (eg. search for different
>values, and even different tables).  I'm assuming that I must continue to 
>prepare these statements as well.

As I mentionned, you will get very significant performance improvements if you
can try and reuse previously prepared statements. I suspect that, even though
the application issues a large number of different SELECT statements, some of
them are used more frequently than others. You may want to add a simple
"statement" cache to your code. The cache would remember a set of SQL
statements, along with their statement id, sqldq, cursor name. When you are
asked by the upper layers of your code to do a certain query, you first check
the cache to see if you already did get the same statement before, and if so,
you can skip the prepare steps. You would need to define some policy for
managing that cache, so that frequently used statements would stay longer. I
believe I have some example code that implements a simple cache of that kind. 
I can mail it to you if you want. 

>Our most important concern is the connection space.  Is there a problem in
>establishing a single connection that persists as long as the vax/vms 
>node continues to operate?  Will the integrity of the data be compromised
>given the update process mentioned in my base note (eg. if a row is 
>modified by the update process and my program is constantly accessed via
>UCX, will that changed row be available to my program?)

No, that should not be a problem in your case (all you do is read-only
queries). If you were doing read-write transactions, or storing/inserting
records, then I would recommend that you disconnect and reconnect periodically.
Note however that the DBA on the server may need to shudtown the database
(and/or the sql/services server). This would then cause errors later on in your
program as it tries to use the database. You may want to catch those errors
and have your program reconnect when they happen.

One point though: the read only transaction lets you read information even
though it is being updated at that same moment. However in that case, your
program will see the data as it was prior to the update, so it may be slightly
stale, like this:

                S    U1    C       S    U2    C      S    U3    C
  Updater:      !----------!       !----------!      !----------!     

                                           S     R1    C
  Reader                                   !-----------!

  Time -------------------------------------------------------->

"S" and "C" indicate the start and end of a transaction. "U" indicates an
update. "R" denotes the reading of the same info.

In this example, the "reader" only sees the update U1. It does not see the
update U2 (it will on the next cycle). This is because the transaction that
did this update was still active when the reader started its read-only
transaction.

If this is not acceptable, then you cqn have the reader use READ WRITE
transactions instead of READ ONLY. However, the reader will then have to wait
for the updater to commit, and it may also block other updaters. A bit like
this (where "." denotes a waiting process):

                S    U1    C       S    U2    C      S       U3    C
  Updater:      !----------!       !----------!      !....----------!     

                                           S       R2    C
  Reader                                   !..-----------!

  Time -------------------------------------------------------->

In this case, however, the reader will always see the most current status of
the shared data.

/albert
2165.4cache code gratefully accepted!ORAREP::VSSCAD::FITZGERALDMon Mar 17 1997 16:1524
Albert,

Can't thank you enough for getting back to me on this one, and I'm very
happy to take you up on the 'prepared/select_stmt_cache' code that you
offered below.

E-mail is: fitzgerald@vsscad.enet.dec.com
Phone: (508) 493-2828

Thanks once again for all your help!
Patti
--------------------------------------------------------------------------------
>As I mentionned, you will get very significant performance improvements if you
>can try and reuse previously prepared statements. I suspect that, even though
>the application issues a large number of different SELECT statements, some of
>them are used more frequently than others. You may want to add a simple
>"statement" cache to your code. The cache would remember a set of SQL
>statements, along with their statement id, sqldq, cursor name. When you are
>asked by the upper layers of your code to do a certain query, you first check
>the cache to see if you already did get the same statement before, and if so,
>you can skip the prepare steps. You would need to define some policy for
>managing that cache, so that frequently used statements would stay longer. I
>believe I have some example code that implements a simple cache of that kind. 
>I can mail it to you if you want.