by Bill Todd
(C) Copyright 2002 by Bill Todd - All Rights Reserved
Since InterBase consists of over a million lines of legacy C code that was not written with the idea of multiprocessor computers in mind, converting the InterBase kernel and related subsystems to provide multiprocessor support may well be the biggest change in the history of the product. This project had several goals.
Making the InterBase engine fully multithreaded was necessary to allow multiple tasks to truly execute concurrently on a multiprocessor machine. However, it also provides a major performance benefit for multiuser applications on single CPU systems. In prior versions of IB once a SQL statement begain execution on a single CPU machine other pending tasks would not gain access to the CPU until the executing statement finished. If a statement took a long time to complete other users applications with statements waiting to be executed would become unresponsive while waiting their turn. InterBase 7's new multithreading architecture allows the CPU to be shared among all running statements according to the operating systems time slicing model. While this does not reduce the total time for all statements to execute it does allow statements to share the CPU so that statements with a short execution time will finish quickly instead of waiting for a long running statement to finish. This presents end-users with the appearance of a faster more responsive system.
InterBase 7 does not support decomposing a single SQL statement into multiple execution threads that can run simultaineously on multiple processors. To take full advantage of InterBase's multiprocessor support you must have a multiuser environment where multiple connections to the InterBase server are executing SQL statements simultaneously.
When designing a method of controlling access to shared variables and data structures in a multithreaded environment the granularity of the locking scheme has a significant impact on performance. It is best to lock and unlock each individual variable and data structure when it is accessed instead of locking entire functions or modules.
Since most accesses to shared variables are read accesses it is also desirable to use a locking scheme that provides shared read locks and exclusive write locks. With this scheme multiple threads can obtain simultaineous read locks on the same variable. As long as a read lock exists no thread can obtain a write lock. When one thread holds a write lock no other thread can obtain either a read or write lock on that varaible or data structure.
Access to shared variables and data structures is controlled using mutexes allocated by the operating system. Not all operating systems support read/write mutexes, for example, Windows does not. For operating systems that do not provide read/write mutexes this functionality is implemented in InterBase.
Using operating system mutexes introduces another problem because allocating a mutex requires both time and resources. In a legacy application with a large number of shared variables and datastructures to protect achieving high lock granularity by allocating a mutex for each variable or data structure would consume too many resources. InterBase achieves both high granularity and low resource usage by creating a pool of shared mutexes. The size of the pool is based on the number of CPU's in the system. When a mutex is requried it is allocated from the pool. When the mutex is no longer needed it is returned to the pool.
Memory access throughout the InterBase engine is controlled by a single central subsystem. This subsystem manages the mutex pool and also mantains statistics and state information that aids the InterBase engineering team in debugging and analyzing problems.
By default the InterBase 7 server uses all of the processors in the system it is running on. If InterBase is not running on a dedicated system you may not want InterBase to use all of the CPU's in the system. The Windows version of InterBase supports the CPU_AFFINITY directive in the ibconfig file. This directive can be used to affine InterBase to any processor or combination of processors in the system. Each processor is identified by a bit so a value of 1 indicates the first processor, 2 the second processor, 4 the third processor and 8 the fourth processor. For example,
CPU_AFFINITY 6
would attach InterBase to the second and third processors in the system. There is no way to control which processors are used on a Linux or Solaris system. On these platforms InterBase will always use all available processors.
If you have a Windows system with multiple processors install InterBase 6.5 and run two or more SQL statements simultaneously while looking at the Performance tab in Task Manager. On a dual CPU system you should see CPU usage at about 50%.
Now install InterBase 7 and repeat the same test. You will see both CPU's being used at the same time.
By default the InterBase 7 engine can have up to 100 threads active at one time. You can change the maximum number of active threads using the new MAX_THREADS parameter in the ibconfig file. For example, the following line limits InterBase 7 to 50 active threads.
MAX_THREADS 50
The best value for MAX_THREADS depends on what the client applications are doing. If many clients are doing the same task you may get improved performance by reducing MAX_THREADS to reduce contention. Where many clients are performing diverse tasks a higher number may work better.
MAX_THREADS does not limit the number of threads that the InterBase Server can create. Lowering MAX_THREADS will not prevent clients from connecting to the server. MAX_THREADS only limits the number of threads that can be active at one time.
While InterBase is largely self tuning and does not require the minstrations of a fulltime DBA, the lack of adequate performance monitoring tools has been a problem for some users. Understanding how resources are being used in a production environment can be important for capacity planning. With resource usage information you can see impending problems before they occur and increase the capacity of the database server before performance degrades and users complain.
Transactions that are left open for a long time can degrade system performance. GSTAT has always provided the oldest interesting transaction number (OIT), oldest active transaction number (OAT) and the next transaction number to let you see if a long running transaction is causing trouble, but the information stopped there. In prior versions of InterBase you had no way to identify the owner of the offending transaction or to terminate it. A runaway query is another problem that requires intervention by the DBA. If a user starts a query that runs for a long time and consumes a lot of system resources performance can degrade for other users. The DBA needs a way to identify the query and either terminate it or reduce its priority to restore system performance.
InterBase has always maintained a great deal of performance information internally but this information as never been accessable before. The ideal way to make performance information available is through a set of temporary tables. Providing performance information in table form lets DBA's and tools vendors examine information using standard SQL queries. Temporary tables can be joined to provide powerful views of the performance information. Using temporary tables and SQL also allows new information to be added to the tables in the form of new columns without breaking existing applications that use the data.
A temporary table is a table that is private to the attachement (connection) that creates it. Unlike a permanent table a temporary table is dropped after the application that creates it detaches from the database. Multiple users can create temporary tables with the same name at the same time without name collisions.
Temporary tables also have an ON COMMIT clause in the their CREATE TEMPORARY TABLE statement that determines what happens to the temporary table's data when the transaction that created the table commits. The syntax is ... ON COMMIT {PRESERVE | DELETE} ROWS. All of the temporary tables used for monitoring the runtime state of InterBase are predefined by the system and have the ON COMMIT DELETE ROWS option.
Before I continue I may as well give you the bad news. Temporary tables are not surfaced for users in InterBase 7. Fortunately, now that 90% of the work has been done, the odds that we will see them in the next release have increased dramatically.
An InterBase database is described by the static metadata in its system tables. The system tables describe the structure of the database. At runtime, however, the InterBase server is very dynamic, even chaotic, with many users attached to variaous databases performing different tasks. The focus of the monitoring features in InterBase 7 is on how existing computing resources are being used by the InterBase server. The resources of interest are the CPU, memory, device I/O and network I/O.
Resource use by four database objects is covered by the monitoring system. The objects are the database, attachments, transactions and statements. For an open database there are database wide parameters that affect the database's performance. These include the OIT, OAT, oldest snapshot transaction number and next transaction number as well as the number of cache buffers currently allocated in the cache manager.
For attachments the username has been available through the API in prior versions but there are other things you need to know about each attachment. These include the IP address of the user, what statements they are running, how long they have been connected and the total amount of I/O to the database.
For active transactions you need to know the transaction number and how long they have been active. Transactions that are never closed are a common source of poor database performance. When performance suffers you not only need to determine if an active transaction is the problem. You also need to identify it and be able to roll it back.
For SQL statements the amount of memory being used and the fraction of CPU time being consumed are important. The number of SQL statements executing and their aggregate resource usage is also important for capacity planning.
Performance data is provided in the eight temporary tables shown in the following table and is available for the database you are currently connected to.
| Table Name |
Description |
| TMP$DATABASE | One row for the database you are connected to. |
| TMP$TRANSACTIONS | One row for each active transaction. |
| TMP$ATTACHMENTS | One row for each attachement to the database. |
| TMP$STATEMENTS | One row for each statement executed since the first attachement to the database. |
| TMP$POOLS | One row for each memory pool currently allocated. |
| TMP$PROCEDURES | One row for each stored procedure loaded since the first attachement to the database. |
| TMP$RELATIONS | One row for each table that is currently open. |
| TMP$POOL_BLOCKS | One row for each block in each memory pool. |
The diagram below shows the relationships between the temporary tables.
To refresh the temporary tables commit your transaction and run your SELECT again. The temporary tables are emptied when the transaction that is accessing them ends.
The following eight tables show the structure of each of the temporary tables. Executing the SHOW SYSTEM command in ISQL will show the temporary tables at the end of the list of system tables.
| Column name |
Data type |
Description |
| TMP$DATABASE_ID |
INTEGER |
database identifier |
| TMP$DATABASE_PATH |
VARCHAR [255] |
database pathname |
| TMP$ATTACHMENTS |
SMALLINT |
number of active attachments |
| TMP$STATEMENTS |
INTEGER |
number of compiled statements |
| TMP$ALLOCATED_PAGES |
INTEGER |
pages allocated to all database files |
| TMP$POOLS |
INTEGER |
number of memory pools |
| TMP$PROCEDURES |
SMALLINT |
number of procedures loaded |
| TMP$RELATIONS |
SMALLINT |
number of relations loaded |
| TMP$TRIGGERS |
SMALLINT |
number of triggers loaded |
| TMP$ACTIVE_THREADS |
SMALLINT |
active threads in database |
| TMP$SORT_MEMORY |
INTEGER |
sort buffer allocated memory |
| TMP$CURRENT_MEMORY |
INTEGER |
current memory allocated database |
| TMP$MAXIMUM_MEMORY |
INTEGER |
maximum memory ever allocated |
| TMP$PERMANENT_POOL_MEMORY |
INTEGER |
permanent pool memory size |
| TMP$CACHE_POOL_MEMORY |
INTEGER |
buffer pool memory size |
| TMP$TRANSACTIONS |
SMALLINT |
number of active transactions |
| TMP$TRANSACTION_COMMITS |
INTEGER |
number of transaction commits |
| TMP$TRANSACTION_ROLLBACKS |
INTEGER |
number of transaction rollbacks |
| TMP$TRANSACTION_PREPARES |
INTEGER |
number of transaction prepares |
| TMP$TRANSACTION_DEADLOCKS |
INTEGER |
number of transaction deadlocks |
| TMP$TRANSACTION_CONFLICTS |
INTEGER |
number of transaction update conflicts |
| TMP$TRANSACTION_WAITS |
INTEGER |
number of transaction wait fors |
| TMP$NEXT_TRANSACTION |
INTEGER |
next transaction number |
| TMP$OLDEST_INTERESTING |
INTEGER |
oldest interesting transaction |
| TMP$OLDEST_ACTIVE |
INTEGER |
oldest active transaction |
| TMP$OLDEST_SNAPSHOT |
INTEGER |
oldest snapshot transaction |
| TMP$CACHE_BUFFERS |
INTEGER |
number of cache buffers |
| TMP$CACHE_PRECEDENCE |
INTEGER |
nodes in cache precedence graph |
| TMP$CACHE_LATCH_WAITS |
INTEGER |
buffer latch waits |
| TMP$CACHE_FREE_WAITS |
INTEGER |
number of waits for a free buffer |
| TMP$CACHE_FREE_WRITES |
INTEGER |
number of writes to free buffers |
| TMP$SWEEP_INTERVAL |
INTEGER |
sweep trigger interval |
| TMP$SWEEP_ACTIVE |
CHAR [1] |
Y (active) N (not-active) |
| TMP$SWEEP_RELATION |
VARCHAR [128] |
relation currently being swept |
| TMP$SWEEP_RECORDS |
INTEGER |
records swept in above relation |
| TMP$PAGE_READS |
INTEGER |
page reads all database files |
| TMP$PAGE_WRITES |
INTEGER |
page writes all database files |
| TMP$PAGE_FETCHES |
INTEGER |
page fetches all database files |
| TMP$PAGE_MARKS |
INTEGER |
page marks all database files |
| TMP$RECORD_SELECTS |
INTEGER |
records selected from database |
| TMP$RECORD_INSERTS |
INTEGER |
records inserted into database |
| TMP$RECORD_UPDATES |
INTEGER |
records updated to database |
| TMP$RECORD_DELETES |
INTEGER |
records deleted from database |
| TMP$RECORD_PURGES |
INTEGER |
garbage collect record purges |
| TMP$RECORD_EXPUNGES |
INTEGER |
garbage collect record expunges |
| TMP$RECORD_BACKOUTS |
INTEGER |
garbage collect record backouts |
| Column name |
Data type |
Description |
| TMP$TRANSACTION_ID |
INTEGER |
transaction number |
| TMP$ATTACHMENT_ID |
INTEGER |
attachment identifier |
| TMP$POOL_ID |
INTEGER |
|
| TMP$POOL_MEMORY |
INTEGER |
|
| TMP$TIMESTAMP |
TIMESTAMP |
start time of attachment |
| TMP$SNAPSHOT |
INTEGER |
snapshot transaction number |
| TMP$QUANTUM |
INTEGER |
units of execution |
| TMP$SAVEPOINTS |
INTEGER |
savepoint number of records |
| TMP$READONLY |
CHAR [1] |
transaction is read only |
| TMP$WRITE |
CHAR [1] |
transaction has written data |
| TMP$NOWAIT |
CHAR [1] |
transaction is no wait |
| TMP$COMMIT_RETAINING |
CHAR [1] |
commit retaining performed |
| TMP$STATE |
VARCHAR [16] |
ACTIVE, LIMBO, COMMITTING, PRECOMMITTED |
| TMP$TYPE |
VARCHAR [16] |
SNAPSHOT, READ_COMMITTED |
| TMP$PAGE_READS |
INTEGER |
page reads all database files |
| TMP$PAGE_WRITES |
INTEGER |
page writes all database files |
| TMP$PAGE_FETCHES |
INTEGER |
page fetches all database files |
| TMP$PAGE_MARKS |
INTEGER |
page marks all database files |
| TMP$RECORD_SELECTS |
INTEGER |
records selected by transaction |
| TMP$RECORD_INSERTS |
INTEGER |
records inserted by transaction |
| TMP$RECORD_UPDATES |
INTEGER |
records updated by transaction |
| TMP$RECORD_DELETES |
INTEGER |
records deleted by transaction |
| TMP$RECORD_PURGES |
INTEGER |
garbage collect record purges |
| TMP$RECORD_EXPUNGES |
INTEGER |
garbage collect record expunges |
| TMP$RECORD_BACKOUTS |
INTEGER |
garbage collect record backouts |
| Column name |
Data type |
Description |
| TMP$ATTACHMENT_ID |
INTEGER |
attachment identifier |
| TMP$DATABASE_ID |
INTEGER |
database identifier |
| TMP$POOL_ID |
INTEGER |
reserved |
| TMP$POOL_MEMORY |
INTEGER |
reserved |
| TMP$STATEMENTS |
SMALLINT |
number of compiled statements |
| TMP$TRANSACTIONS |
SMALLINT |
number of active transactions |
| TMP$TIMESTAMP |
TIMESTAMP |
attachment create timestamp |
| TMP$QUANTUM |
INTEGER |
units of execution |
| TMP$USER |
VARCHAR [31] |
user name |
| TMP$USER_IP_ADDR |
VARCHAR [16] |
user IP address |
| TMP$USER_HOST_NAME |
VARCHAR [16] |
user host name |
| TMP$USER_PROCESS_ID |
VARCHAR [16] |
user process ID |
| TMP$STATE |
VARCHAR [16] |
CONNECTED, ACTIVE |
| TMP$PRIORITY |
VARCHAR [16] |
reserved |
| TMP$DBKEY_ID |
INTEGER |
transaction ID of dbkey |
| TMP$ACTIVE_SORTS |
SMALLINT |
number of active sorts |
| TMP$PAGE_READS |
INTEGER |
page reads all database files |
| TMP$PAGE_WRITES |
INTEGER |
page writes all database files |
| TMP$PAGE_FETCHES |
INTEGER |
page fetches all database files |
| TMP$PAGE_MARKS |
INTEGER |
page marks all database files |
| TMP$RECORD_SELECTS |
INTEGER |
records selected by attachment |
| TMP$RECORD_INSERTS |
INTEGER |
records inserted by attachment |
| TMP$RECORD_UPDATES |
INTEGER |
records updated by attachment |
| TMP$RECORD_DELETES |
INTEGER |
records deleted by attachment |
| TMP$RECORD_PURGES |
INTEGER |
garbage collect record purges |
| TMP$RECORD_EXPUNGES |
INTEGER |
garbage collect record expunges |
| TMP$RECORD_BACKOUTS |
INTEGER |
garbage collect record backouts |
| Column name |
Data type |
Description |
| TMP$STATEMENT_ID |
INTEGER |
statement identifier |
| TMP$ATTACHMENT_ID |
INTEGER |
attachment identifier |
| TMP$TRANSACTION_ID |
INTEGER |
transaction number |
| TMP$SQL |
VARCHAR [2048] |
SQL string |
| TMP$BLR |
VARCHAR [2048] |
BLR string |
| TMP$POOL_ID |
INTEGER |
pool identifier |
| TMP$POOL_MEMORY |
INTEGER |
pool memory size |
| TMP$CLONE |
SMALLINT |
cloned instance number |
| TMP$TIMESTAMP |
TIMESTAMP |
start time of statement |
| TMP$QUANTUM |
INTEGER |
units of execution |
| TMP$INVOCATIONS |
INTEGER |
number of calls to statement |
| TMP$STATE |
VARCHAR [16] |
ACTIVE, INACTIVE, STALLED, CANCELLED |
| TMP$PRIORITY |
VARCHAR [16] |
reserved |
| TMP$PAGE_READS |
INTEGER |
page reads all database files |
| TMP$PAGE_WRITES |
INTEGER |
page writes all database files |
| TMP$PAGE_FETCHES |
INTEGER |
page fetches all database files |
| TMP$PAGE_MARKS |
INTEGER |
page marks all database files |
| TMP$RECORD_SELECTS |
INTEGER |
records selected by statement |
| TMP$RECORD_INSERTS |
INTEGER |
records inserted by statement |
| TMP$RECORD_UPDATES |
INTEGER |
records updated by statement |
| TMP$RECORD_DELETES |
INTEGER |
records deleted by statement |
| TMP$RECORD_PURGES |
INTEGER |
garbage collect record purges |
| TMP$RECORD_EXPUNGES |
INTEGER |
garbage collect record expunges |
| TMP$RECORD_BACKOUTS |
INTEGER |
garbage collect record backouts |
| Column name |
Data type |
Description |
| TMP$POOL_ID |
INTEGER |
pool identifier |
| TMP$POOL_TYPE |
VARCHAR [16] |
pool type |
| TMP$POOL_MEMORY |
INTEGER |
total memory in pool |
| TMP$FREE_MEMORY |
INTEGER |
free memory in pool |
| TMP$EXTEND_MEMORY |
INTEGER |
memory by which pool extended |
| TMP$FREE_STACK_NODES |
SMALLINT |
free linked list stack nodes |
| TMP$FREE_BITMAP_BUCKETS |
SMALLINT |
free bitmap buckets |
| TMP$FREE_BITMAP_SEGMENTS |
INTEGER |
free bitmap segments |
| Column name |
Data type |
Description |
| TMP$PROCEDURE_ID |
INTEGER |
procedure identifier |
| TMP$DATABASE_ID |
INTEGER |
database identifier |
| TMP$PROCEDURE_NAME |
VARCHAR [128] |
procedure name |
| TMP$POOL_ID |
INTEGER |
pool identifier |
| TMP$POOL_MEMORY |
INTEGER |
pool memory size |
| TMP$CLONE |
SMALLINT |
cloned instance number |
| TMP$TIMESTAMP |
TIMESTAMP |
start time of procedure |
| TMP$USE_COUNT |
SMALLINT |
statements compiled with procedure |
| TMP$QUANTUM |
INTEGER |
units of execution |
| TMP$INVOCATIONS |
INTEGER |
number of calls to procedure |
| TMP$PAGE_READS |
INTEGER |
page reads all database files |
| TMP$PAGE_WRITES |
INTEGER |
page writes all database files |
| TMP$PAGE_FETCHES |
INTEGER |
page fetches all database files |
| TMP$PAGE_MARKS |
INTEGER |
page marks all database files |
| TMP$RECORD_SELECTS |
INTEGER |
records selected by procedure |
| TMP$RECORD_INSERTS |
INTEGER |
records inserted by procedure |
| TMP$RECORD_UPDATES |
INTEGER |
records updated by procedure |
| TMP$RECORD_DELETES |
INTEGER |
records deleted by procedure |
| TMP$RECORD_PURGES |
INTEGER |
garbage collect record purges |
| TMP$RECORD_EXPUNGES |
INTEGER |
garbage collect record expunges |
| TMP$RECORD_BACKOUTS |
INTEGER |
garbage collect record backouts |
| Column name |
Data type |
Description |
| TMP$RELATION_ID |
INTEGER |
relation identifier |
| TMP$DATABASE_ID |
INTEGER |
database identifier |
| TMP$RELATION_NAME |
VARCHAR [128] |
relation name |
| TMP$USE_COUNT |
SMALLINT |
statements compiled against relation |
| TMP$SWEEP_COUNT |
SMALLINT |
database sweep or garbage collector |
| TMP$SCAN_COUNT |
INTEGER |
sequential scans |
| TMP$FORMATS |
SMALLINT |
number of relation formats |
| TMP$POINTER_PAGES |
INTEGER |
number of relation pointer pages |
| TMP$DATA_PAGES |
INTEGER |
number of relation data pages |
| TMP$GARBAGE_COLLECT_PAGES |
INTEGER |
number of data pages to garbage collect |
| TMP$PAGE_READS |
INTEGER |
page reads all database files |
| TMP$PAGE_WRITES |
INTEGER |
page writes all database files |
| TMP$PAGE_FETCHES |
INTEGER |
page fetches all database files |
| TMP$PAGE_MARKS |
INTEGER |
page marks all database files |
| TMP$RECORD_IDX_SELECTS |
INTEGER |
records selected by index retrieval |
| TMP$RECORD_SEQ_SELECTS |
INTEGER |
records selected by sequential scan |
| TMP$RECORD_INSERTS |
INTEGER |
records inserted into relation |
| TMP$RECORD_UPDATES |
INTEGER |
records updated in relation |
| TMP$RECORD_DELETES |
INTEGER |
records deleted from relation |
| TMP$RECORD_PURGES |
INTEGER |
garbage collect record purges |
| TMP$RECORD_EXPUNGES |
INTEGER |
garbage collect record expunges |
| TMP$RECORD_BACKOUTS |
INTEGER |
garbage collect record backouts |
| Column name |
Data type |
Description |
| TMP$POOL_ID |
INTEGER |
|
| TMP$ACC |
INTEGER |
|
| TMP$ARR |
INTEGER |
|
| TMP$ATT |
INTEGER |
|
| TMP$BCB |
INTEGER |
buffer control block |
| TMP$BDB |
INTEGER |
buffer descriptor block |
| TMP$BLB |
INTEGER |
blob block |
| TMP$BLF |
INTEGER |
|
| TMP$BTB |
INTEGER |
|
| TMP$BTC |
INTEGER |
|
| TMP$CHARSET |
INTEGER |
|
| TMP$CSB |
INTEGER |
compiler scratch block |
| TMP$CSCONVERT |
INTEGER |
|
| TMP$DBB |
INTEGER |
database block |
| TMP$DCC |
INTEGER |
data compression control block |
| TMP$DFW |
INTEGER |
deferred work block |
| TMP$DLS |
INTEGER |
|
| TMP$EXT |
INTEGER |
|
| TMP$FIL |
INTEGER |
file block |
| TMP$FLD |
INTEGER |
|
| TMP$FMT |
INTEGER |
format block |
| TMP$FRB |
INTEGER |
free block |
| TMP$FUN |
INTEGER |
|
| TMP$HNK |
INTEGER |
hunk block |
| TMP$IDB |
INTEGER |
|
| TMP$IDL |
INTEGER |
|
| TMP$IRB |
INTEGER |
|
| TMP$IRL |
INTEGER |
|
| TMP$LCK |
INTEGER |
lock block |
| TMP$LWT |
INTEGER |
|
| TMP$MAP |
INTEGER |
|
| TMP$MFB |
INTEGER |
|
| TMP$NOD |
INTEGER |
node block |
| TMP$OPT |
INTEGER |
|
| TMP$PRC |
INTEGER |
|
| TMP$PRE |
INTEGER |
precedence block |
| TMP$PRM |
INTEGER |
|
| TMP$REC |
INTEGER |
record block |
| TMP$REL |
INTEGER |
relation block |
| TMP$REQ |
INTEGER |
request block |
| TMP$RIV |
INTEGER |
|
| TMP$RSB |
INTEGER |
record source block |
| TMP$RSC |
INTEGER |
|
| TMP$SAV |
INTEGER |
|
| TMP$SBM |
INTEGER |
sparse bitmap block |
| TMP$SCL |
INTEGER |
|
| TMP$SDW |
INTEGER |
|
| TMP$SMB |
INTEGER |
sort map block |
| TMP$SRPB |
INTEGER |
|
| TMP$STR |
INTEGER |
string block |
| TMP$SVC |
INTEGER |
|
| TMP$SYM |
INTEGER |
|
| TMP$TEXTTYPE |
INTEGER |
|
| TMP$TFB |
INTEGER |
temporary field block |
| TMP$TPC |
INTEGER |
|
| TMP$TRA |
INTEGER |
transaction block |
| TMP$USR |
INTEGER |
|
| TMP$VCL |
INTEGER |
vector long block |
| TMP$VCT |
INTEGER |
|
| TMP$VCX |
INTEGER |
|
| TMP$XCP |
INTEGER |
|
To query the InterBase temporary tables you must connect to an InterBase database. The information in the temporary tables is for that database only. For example, if you issue the query
SELECT TMP$USER, TMP$USER_IP_ADDR FROM TMP$ATTACHMENTS
you will get a list of all of the users connected to the database that you are connected to. If other users are attached to other databases you will not see them in the list. If users work with more than one database on the same server and you want to know the total number of attached users you must connect to each database in turn, query the number of attachemtns, then total the results of all of the queries. The same is true of the other tables. If you query TMP$DATABASE for the number of active transactions you will get the number of active transactions in the database you are connected to.
Querying the TMP$ tables is no different than querying any other tables. You can use all of the features of InterBase SQL. You can also create views and stored procedures that return information from the TMP$ tables.
The following query returns a number of useful statistics about the database you are connected to. Calculated fields are used to show the difference between the oldest active transaction and the oldest interesting transaction and the ratio of pages read from the cache to pages read from disk.
SELECT TMP$DATABASE_PATH, TMP$ATTACHMENTS, TMP$ACTIVE_THREADS, TMP$MAXIMUM_MEMORY, TMP$TRANSACTIONS, TMP$TRANSACTION_COMMITS, TMP$TRANSACTION_ROLLBACKS, TMP$TRANSACTION_DEADLOCKS, TMP$TRANSACTION_CONFLICTS, TMP$NEXT_TRANSACTION, TMP$OLDEST_ACTIVE, TMP$OLDEST_INTERESTING, (TMP$OLDEST_ACTIVE - TMP$OLDEST_INTERESTING) AS TMP$INTERESTING_INACTIVE, TMP$PAGE_READS, TMP$PAGE_WRITES, TMP$PAGE_FETCHES, (TMP$PAGE_FETCHES / TMP$PAGE_READS) AS TMP$CACHE_RATIO, TMP$SWEEP_ACTIVE FROM TMP$DATABASE;
If you want to see what is happening to your database over time create the following table and stored procedure. Write an application that calls LOG_DB_STATISTICS at regular intervals and you will build a picture of what happens as your database is being used.
CREATE TABLE DB_STATISTICS ( STAT_DATE DATE, STAT_TIME TIME, ATTACHMENTS INTEGER, ACTIVE_THREADS INTEGER, MAXIMUM_MEMORY INTEGER, ACTIVE_TRANSACTIONS INTEGER, COMMITS INTEGER, ROLLBACKS INTEGER, DEADLOCKS INTEGER, CONFLICTS INTEGER, NEXT_TRANSACTION INTEGER, OAT INTEGER, OIT INTEGER, OAT_MINUS_OIT INTEGER, PAGE_READS INTEGER, PAGE_WRITES INTEGER, PAGE_FETCHES INTEGER, FETCH_RATIO INTEGER, SWEEP_ACTIVE CHAR(1) )
CREATE PROCEDURE LOG_DB_STATISTICS AS BEGIN INSERT INTO DB_STATISTICS SELECT CURRENT_DATE, CURRENT_TIME, TMP$ATTACHMENTS, TMP$ACTIVE_THREADS, TMP$MAXIMUM_MEMORY, TMP$TRANSACTIONS, TMP$TRANSACTION_COMMITS, TMP$TRANSACTION_ROLLBACKS, TMP$TRANSACTION_DEADLOCKS, TMP$TRANSACTION_CONFLICTS, TMP$NEXT_TRANSACTION, TMP$OLDEST_ACTIVE, TMP$OLDEST_INTERESTING, (TMP$OLDEST_ACTIVE - TMP$OLDEST_INTERESTING) AS TMP$INTERESTING_INACTIVE, TMP$PAGE_READS, TMP$PAGE_WRITES, TMP$PAGE_FETCHES, (TMP$PAGE_FETCHES / TMP$PAGE_READS) AS TMP$CACHE_RATIO, TMP$SWEEP_ACTIVE FROM TMP$DATABASE; END
This query shows the ten statements with the most execution time in descending order.
SELECT a.tmp$user, s.tmp$timestamp, s.tmp$sql, s.tmp$quantum FROM tmp$statements s, tmp$attachments a WHERE a.tmp$attachment_id = s.tmp$attachment_id ORDER BY s.tmp$quantum DESC ROWS 10;
The following statement shows the ten most often executed stored procedures.
SELECT TMP$PROCEDURE_NAME, TMP$INVOCATIONS, TMP$QUANTUM, TMP$PAGE_READS, TMP$PAGE_WRITES, (TMP$PAGE_READS + TMP$PAGE_WRITES) AS TMP$PAGE_IO, TMP$PAGE FETCHES FROM TMP$PROCEDURES ORDER BY TMP$INVOCATIONS DESC ROWS 10;
This statement shows the ten stored procedures that have the highest total execution time.
SELECT TMP$PROCEDURE_NAME, TMP$INVOCATIONS, TMP$QUANTUM, TMP$PAGE_READS, TMP$PAGE_WRITES, (TMP$PAGE_READS + TMP$PAGE_WRITES) AS TMP$PAGE_IO, TMP$PAGE FETCHES FROM TMP$PROCEDURES ORDER BY TMP$QUANTUM DESC ROWS 10;
This query shows the 50 longest running active transactions in descending order by execution time.
SELECT T.TMP$TRANSACTION_ID, T.TMP$TIMESTAMP, T.TMP$STATE, T.TMP$QUANTUM, T.TMP$POOL_MEMORY, A.TMP$USER, A.TMP$USER_IP_ADDR FROM TMP$TRANSACTIONS T JOIN TMP$ATTACHMENTS A ON T.TMP$ATTACHMENT_ID = A.TMP$ATTACHMENT_ID ORDER BY T.TMP$TIMESTAMP ROWS 50
This statement returns the top 50 transactions by the amount of execution time they have used.
SELECT T.TMP$TRANSACTION_ID, T.TMP$TIMESTAMP, T.TMP$STATE, T.TMP$QUANTUM, T.TMP$POOL_MEMORY, A.TMP$USER, A.TMP$USER_IP_ADDR FROM TMP$TRANSACTIONS T JOIN TMP$ATTACHMENTS A ON T.TMP$ATTACHMENT_ID = A.TMP$ATTACHMENT_ID ORDER BY T.TMP$QUANTUM DESC ROWS 50
This statement selects the top 50 transactions based on the amount of pool memory used.
SELECT T.TMP$TRANSACTION_ID, T.TMP$TIMESTAMP, T.TMP$STATE, T.TMP$QUANTUM, T.TMP$POOL_MEMORY, A.TMP$USER, A.TMP$USER_IP_ADDR FROM TMP$TRANSACTIONS T JOIN TMP$ATTACHMENTS A ON T.TMP$ATTACHMENT_ID = A.TMP$ATTACHMENT_ID ORDER BY T.TMP$POOL_MEMORY DESC ROWS 50
This query shows the number of active transactions and the number of rows selected, inserted, updated and deleted by the user specified in the WHERE clause. Note that this query can return multiple rows if the user has multiple connections to the database. If you want the totals for all of the user's connections use the second query below.
SELECT TMP$USER, TMP$USER_IP_ADDR, TMP$TIMESTAMP, TMP$STATE, TMP$TRANSACTIONS, TMP$RECORD_SELECTS, TMP$RECORD_INSERTS, TMP$RECORD_UPDATES, TMP$RECORD_DELETES FROM TMP$ATTACHMENTS WHERE TMP$USER = 'SYSDBA'
SELECT TMP$USER, SUM(TMP$TRANSACTIONS) AS TMP$TRANSACTIONS, SUM(TMP$RECORD_SELECTS) AS TMP$RECORD_SELECTS, SUM(TMP$RECORD_INSERTS) AS TMP$RECORD_INSERTS, SUM(TMP$RECORD_UPDATES) AS TMP$RECORD_UPDATES, SUM(TMP$RECORD_DELETES) AS TMP$RECORD_DELETES FROM TMP$ATTACHMENTS WHERE TMP$USER = 'SYSDBA' GROUP BY TMP$USER
This query lists connections by total execution time.
SELECT A.TMP$USER, A.TMP$USER_IP_ADDR, A.TMP$QUANTUM, A.TMP$POOL_MEMORY, (A.TMP$PAGE_READS + A.TMP$PAGE_WRITES) AS TMP$PAGE_IO, A.TMP$TIMESTAMP FROM TMP$ATTACHMENTS A ORDER BY A.TMP$QUANTUM DESC
The following SELECT lists all connections in descending order by the total number of disk reads and writes.
SELECT A.TMP$USER, A.TMP$USER_IP_ADDR, A.TMP$QUANTUM, A.TMP$POOL_MEMORY, (A.TMP$PAGE_READS + A.TMP$PAGE_WRITES) AS TMP$PAGE_IO, A.TMP$TIMESTAMP FROM TMP$ATTACHMENTS A ORDER BY 5 DESC
You can also update some of the temporary tables to control InterBase. Suppose you identify a transaction that has been active for too long and you want to roll it back.
UPDATE TMP$TRANSACTION SET TMP$STATE = 'ROLLBACK' WHERE (TMP$TRANSACTION_ID = 12345)
To rollback a limbo transaction:
UPDATE TMP$TRANSACTION SET TMP$STATE = 'ROLLBACK' WHERE (TMP$TRANSACTION_ID = 12345)
To commit a limbo transaction:
UPDATE TMP$TRANSACTION SET TMP$STATE = 'COMMIT' WHERE (TMP$TRANSACTION_ID = 12345)
To cancel an attachment's current operation:
UPDATE TMP$ATTACHMENTS SET TMP$STATE = 'CANCEL' WHERE (TMP$ATTACHMENT_ID = 12345)
To shutdown an attachment set the attachment's state to SHUTDOWN. Shutting down an attachment detaches the user from the database and disconnects the user's connection to the server.
UPDATE TMP$ATTACHMENTS SET TMP$STATE = 'SHUTDOWN' WHERE (TMP$ATTACHMENT_ID = 12345)
To stop an executing statement:
UPDATE TMP$STATEMENTS SET TMP$STATE = 'CANCEL' WHERE (TMP$STATEMENT_ID = 12345)
InterBase 6.5 introduced the ability to grant and revoke priviledges on the InterBase system tables. The system tables have a default priviledge of SELECT for PUBLIC. The temporary tables used for performance monitoring are accessible by the database owner and SYSDBA only. One of those users must grant access to any other users that require it.
The names of objects in an InterBase database are now limited to 67 characters plus a null terminator.
IB 7 introduces a new on disk structure, ODS 11. This new structure is required to support the new Boolean data type and the new 68 character metadata names. IB 7 can still read ODS 10 databases. You can convert a database from ODS 10 to ODS 11 by backing it up and restoring it using IB 7.
The default file extension for IB database files has been changed from .GDB to .IB. This change was made to eliminate the conflict between the .GDB extension and the System Restore facility on Windows ME and XP. System Restore automatically copies files with the .GDB extension each time the fiel is touched. This causes performance to suffer. Switching to the .IB extension eliminates this problem.
The IB security database has been renamed from ISC4.GDB to ADMIN.IB. To continue using your existing security database back it up and restore it using IB 7.
With IB 7 you can use any name you choose for the security database. The ibconfig file contains a new parameter, ADMIN_DB, that specifies the name for the security database. This parameter has the form:
ADMIN_DB DBName.EXT
The IB configuration file, formerly named isc_config on Linux and Solaris, has been renamed ibconfig for consistency across platforms.
The following keywords are new in InterBase 7.
The following are likely to become keywords in a future realease.
InterBase 7 supports a SQL 99 compliant Boolean data type. The Boolean type is implemented as a 16 bit integer and can have one of three values; True, False or Unknown. Unknown indicates that the Boolean field is null.
Example:
CREATE TABLE AWARDS_1 (
IS_ELIGIBLE BOOLEAN,
NAME VARCHAR(20)
);
INSERT INTO AWARDS_1 VALUES(TRUE, 'Jim Smith');
INSERT INTO AWARDS_1 VALUES(FALSE, 'John Butler');
SELECT * FROM AWARDS_1 WHERE isEligible = TRUE;
Executing a query, using IBConsole, against a table with a Boolean field will return True, False or Unknown. Executing the same query using the API functions will return 1 for True, 0 for False and NULL for Unknown.
For ESQL and DSQL programmers, we define the following type in ibase.h:
define SQL_BOOLEAN 590
Calling SET TERM to define an alternate terminating character is no longer necessary when creating stored procedures and triggers. InterBase will parse CREATE TRIGGER and CREATE PROCEDURE statements correctly using the default terminator which is a semicolon. SET TERM still works so old scripts will run without change. IBConsole and InterBase Express still require the use of SET TERM.
To solve potential security problems with external tables the location for external tables is now restricted. External tables must be in one of two locations.
Three new API functions let applications determine the InterBase client version.
InterClient is now a type 4 JDBC driver. It is no longer necessary to install InterServer on your InterBase server to use JDBC connectivity.
If you do not wish to upgrade all of your clients to the new type 4 driver you can continue to run InterServer on your InterBase server. with InterServer running both type 3 and type 4 InterClient drivers will be able to connect to your InterBase server.
To upgrade clients to the new type 4 driver copy the new interclient.jar file to the machine and make sure it is the first instance of interclient.jar on the CLASSPATH.
(C) Copyright 2002 by Bill Todd - All Rights Reserved. Reproduction in any form without the written consent of the author is prohibited.