Introduction to Globals
One of the central features of InterSystems IRIS® is its multidimensional storage engine. This feature lets applications store data in compact, efficient, multidimensional sparse arrays. These arrays are referred to as globals.
A global is a subscripted variable that can store any type of data. Stored on disk, the data is globally available across processes, hence the name “global.” A global is differentiated from a regular variable by placing a caret (^) in front of the name.
People commonly refer to globals as being sparse, multidimensional arrays because of their array-like syntax and because not every subscript in the array must include data, for example:
^a(1,2,3) = 4
^a(1,2,5000) = 4
However, unlike arrays in many languages, the subscripts of a global can be negative numbers, real numbers, or strings, for example:
^b(-4, "hello", 3.14) = 4
For this reason, many people conceptualize globals as dictionaries, or nested dictionaries, with key/value pairs. The following example stores birds according to their scientific names:
^bird("Anatidae", "Aix", "sponsa") = "Wood Duck"
^bird("Anatidae", "Anas", "rubripes") = "American Black Duck"
^bird("Anatidae", "Branta", "leucopsis") = "Barnacle Goose"
^bird("Odontophoridae", "Callipepia", "californica") = "California Quail"
^bird("Odontophoridae", "Callipepia", "gambelii") = "Gambel's Quail"
In many languages, dictionaries are unordered, meaning that when you retrieve data from the dictionary, the data can be returned in some unspecified order. With globals, however, data is sorted according to its subscripts as it is stored.
It is more accurate to visualize a global as an ordered tree, where each node in the tree can have a value and/or children. In this regard, it is more flexible than the nested dictionary model, where typically only the leaves of the tree contain data. In the following example, the root nodes stores a description of the global, while a node representing a family of birds stores a description of that family:
^bird="Birds of North America"
^bird("Anatidae") = "Ducks, Geese and Swans"
^bird("Anatidae", "Aix", "sponsa") = "Wood Duck"
^bird("Anatidae", "Anas", "rubripes") = "American Black Duck"
^bird("Anatidae", "Branta", "leucopsis") = "Barnacle Goose"
^bird("Odontophoridae") = "New World Quails"
^bird("Odontophoridae", "Callipepia", "californica") = "California Quail"
^bird("Odontophoridae", "Callipepia", "gambelii") = "Gambel's Quail"
For an animated illustration of how data is stored in ordered trees, see Ordered Trees.
Features
Globals provide an easy-to-use way to store data in persistent, multidimensional arrays.
For example, you can associate the value “Red” with the key “Color” using a global named ^Settings:
SET ^Settings("Color")="Red"
You can take advantage of the multidimensional nature of globals to define a more complex structure:
SET ^Settings("Auto1","Properties","Color") = "Red"
SET ^Settings("Auto1","Properties","Model") = "SUV"
SET ^Settings("Auto2","Owner") = "Mo"
SET ^Settings("Auto2","Properties","Color") = "Green"
Globals have the following features:
-
Simple to use — Globals are as easy to use as other programming language variables.
-
Multidimensional — You can specify the address of a node within a global using any number of subscripts. For example, in ^Settings("Auto2","Properties","Color"), the subscript Color is a third-level node within the Settings global. Subscripts can be integer, numeric, or string values, and need not be contiguous.
-
Sparse — The subscripts used to address global nodes are highly compacted and need not have contiguous values.
-
Efficient — The operations on globals — inserting, updating, deleting, traversing, and retrieving — are all highly optimized for maximum performance and concurrency. There are additional commands for specialized operations (such as bulk inserts of data). There is a special set of globals designed for temporary data structures (such as for sorting records).
-
Reliable — The InterSystems IRIS database provides a number of mechanisms to ensure the reliability of data stored within globals, including both logical-level and physical-level journaling. Data stored within globals is backed up when a database backup operation is performed.
-
Distributed — InterSystems IRIS provides a number of ways to control the physical location of data stored within globals. You can define a physical database used to store a global, or distribute portions of a global across several databases. Using the distributed database features of InterSystems IRIS, you can share globals across a network of database and application server systems. In addition, by means of mirroring technology, data stored within globals on one system can be automatically replicated on another system.
-
Concurrent — Globals support concurrent access among multiple processes. Setting and retrieving values within individual nodes (array elements) is always atomic: no locking is required to guarantee reliable concurrent access. In addition, InterSystems IRIS supports a powerful set of locking operations that can be used to provide concurrency for more complex cases involving multiple nodes. When using object or SQL access, this concurrency is handled automatically.
-
Transactional — InterSystems IRIS provides commands that define transaction boundaries; you can start, commit, or rollback a transaction. In the event of a rollback, all modifications made to globals within the transaction are undone; the contents of the database are restored to their pre-transaction state. By using the various InterSystems IRIS locking operations in conjunction with transactions, you can perform traditional ACID transactions using globals. (An ACID transaction provides Atomicity, Consistency, Isolation, and Durability.) When using object or SQL access, transactions are handled automatically.
The globals described in this document should not be confused with another type of InterSystems IRIS array variable: process-private globals. Process-private globals are not persistent; they persist only for the duration of the process that created them. Process-private globals are also not concurrent; they can only be accessed by the process that created them. A process-private global can be easily distinguished from a global by its multi-character name prefix: either ^|| or ^|"^"|.
Examples
A simple example can demonstrate the ease and performance of globals. The following program example creates a 10,000–node array (deleting it first if present) and stores it in the database. You can try this to get a sense of the performance of globals:
Creating a Persistent Array
Set start = $ZH // get current time
Kill ^Test.Global
For i = 1:1:10000 {
Set ^Test.Global(i) = i
}
Set elap = $ZH - start // get elapsed time
Write "Time (seconds): ",elap
We can also see how long it takes to iterate over and read the values in the array (make sure to run the above example first to build the array):
Reading a Persistent Array
Set start = $ZH // get current time
Set total = 0
Set count = 0
// get key and value for first node
Set i = $Order(^Test.Global(""),1,data)
While (i '= "") {
Set count = count + 1
Set total = total + data
// get key and value for next node
Set i = $Order(^Test.Global(i),1,data)
}
Set elap = $ZH - start // get elapsed time
Write "Nodes: ",count,!
Write "Total: ",total,!
Write "Time (seconds): ",elap,!
Use in Applications
Within InterSystems IRIS applications, globals are used in many ways, including:
-
As the underlying storage mechanism shared by the object and SQL engines.
-
As the mechanism used to provide a variety of indices, including bitmap indices, for object and SQL data.
-
As a work space for performing certain operations that may not fit within process memory. For example, the SQL engine uses temporary globals for sorting data when there is no preexisting index available for this purpose.
-
For performing specialized operations on persistent objects or SQL tables that are difficult or inefficient to express in terms of object or SQL access. For example, you can define a method (or stored procedure or web method) to perform specialized analysis on data held in a table. By using methods, such an operation is completely encapsulated; the caller simply invokes the method.
-
To implement application-specific, customized storage structures. Many applications have the need to store data that is difficult to express relationally. Using globals you can define custom structures and make them available to outside clients via object methods.
-
For a variety of special purpose data structures used by the InterSystems IRIS system, such as configuration data, class definitions, error messages, and executable code.
Globals are not constrained by the confines of the relational model. They provide the freedom to develop customized structures optimized for specific applications. For many applications, judicious use of globals can be a secret weapon delivering performance that relational application developers can only dream about.
Whether your application makes direct use of globals or not, it is useful to understand their operation. Understanding globals and their capabilities will help you to design more efficient applications as well as provide help with determining the optimal deployment configuration for your applications.