Yes! SAP HANA can make time travel happen. Literally!!
(Image source: http://images5.fanpop.com/image/photos/26500000/Back-To-The-Future-Trilogy-back-to-the-future-265816...)
During our exploration of SAP HANA, we found that SAP has made time travel possible via SAP HANA. This is because SAP HANA runs on SAP In-Memory Computing Engine, which provides support for History Tables. These tables, known as 'HISTORY COLUMN' tables, have session type as ‘HISTORY’ and they support time travel queries.
‘Time travel’ queries are the queries against historical states of the database. In a way, it allows to fetch the historical values (say, some inventory statistics for date 1 Jan 2011 in the table CURRENT_INVENTORY), without actually having to load the data from backups taken on 1 Jan 2011.
This concept (and specially this emotional touch of TRAVELLING through time) caught us, and we ended up exploring this concept in the following manner. All the steps and information sources were duly documented, so that other interested enthusiasts can also enjoy this experience in their own labs.
Following is the basic procedure for using Time Travel Queries in SAP HANA:
The SAP HANA database provides support for a new table type called History Tables. In such History Tables, updates to and deletion of a record results in a new version of the existing record, with the original record being invalidated.
Syntax for creating a History Table:
Let us create a simple history table MODEL_HISTORY_TABLE, which holds the information about the ‘key’ as the primary key, and a column ‘value’ that holds relevant values.
CREATE HISTORY COLUMN TABLE "PRACTICE_TEST"."MODEL_HISTORY_TABLE"
("KEY" VARCHAR (2) NOT NULL DEFAULT '',
"VALUE" INTEGER,
PRIMARY KEY ("KEY")
);
In case it is subsequently determined that a standard column table requires history, then the table can be modified into a history table using the alter table command. For more details, see the link CREATE TABLE, and the document ‘0204 - Modeling - Time Travel Example.pdf’, section ‘Introduction’,
which is available as a zipped content at http://www.experiencesaphana.com/servlet/JiveServlet/downloadBody/2171-102-4-4396/SAPHANA_TechnicalD....
Notes: [Source: http://help.sap.com/hana/html/sql_create_table_history_time_travel.html]
Select SCHEMA_NAME, TABLE_NAME, TABLE_TYPE, SESSION_TYPE from sys.tables where table_name like 'MODEL_HISTORY_TABLE'
Output:
Figure 1. Session_Type for a history table
In order for time travel to work, the Auto commit option of SAP HANA DB needs to be turned off. This limits the number of Commit IDs that needs to be worked with. Besides, if not done, an exception will be thrown with an appropriate error message. (Reference: http://help.sap.com/hana/html/sql_create_table_history_time_travel.html ).
Steps for turning off Auto Commit Option:
2. In the properties window at the bottom of screen, select ‘Off’ against “Auto Commit” option.
To insert the initial few rows of data, following syntax statements were used:
INSERT INTO "PRACTICE_TEST"."MODEL_HISTORY_TABLE" VALUES ('AA', 1);
INSERT INTO "PRACTICE_TEST"."MODEL_HISTORY_TABLE" VALUES ('BB', 2);
INSERT INTO "PRACTICE_TEST"."MODEL_HISTORY_TABLE" VALUES ('CC', 2);
COMMIT;
UPDATE "PRACTICE_TEST"."MODEL_HISTORY_TABLE" MERGE DELTA INDEX;
Since auto-commit is turned off, writing a commit statement and then doing a merge delta after every set of transactions is a must.
The historical state of the History table can be referenced in two ways, either by using the Commit ID, or via UTC time stamping. Details on actual usage is described in the next section (Executing Time Travel Queries).
Since Auto Commit has been turned off, the COMMIT command is necessary to ensure that the data is inserted into the table. So after every transactions is complete, commit statement should be used to commit the values into the database. Each commit statement SAP HANA is marked internally with a commit ID, which can be viewed using following syntax:
SELECT LAST_COMMIT_ID FROM M_TRANSACTIONS
WHERE CONNECTION_ID = CURRENT_CONNECTION;
<commit_id> can also be obtained from m_history_index_last_commit_id after each commit. These values are used later on to reference back to any historical state of the database, when the transactions were performed on the database.
The history of transactions can be validated by viewing the default hidden columns ‘$validfrom$’ and ‘$validto$’ of the history tables:
SELECT *, "$validfrom$", "$validto$"
FROM "PRACTICE_TEST"."MODEL_HISTORY_TABLE" ('REQUEST_FLAGS'='ALLROWS');
The hidden columns “$validfrom$” and “$validto$” (case sensitive) contain the Commit ID when the record was added – “$validfrom$” – and superceded or deleted - “$validto$”.
A question mark (?) under the $validto$ column represents that the data in these rows is still valid (they don’t have any end date yet).
To make our example more lively, let us add few more tables and rows.
Let us add another history table ‘COLOUR_HISTORY_TABLE’ that holds information about the ‘VALUE’ (same as used in the above history table),
and another column ‘HUE’.
CREATE HISTORY COLUMN TABLE "PRACTICE_TEST"."COLOUR_HISTORY_TABLE"(
"VALUE" INTEGER NOT NULL DEFAULT 0,
"HUE" VARCHAR (10),
PRIMARY KEY ("VALUE"));
INSERT INTO "PRACTICE_TEST"."COLOUR_HISTORY_TABLE" VALUES (1, 'GREEN');
INSERT INTO "PRACTICE_TEST"."COLOUR_HISTORY_TABLE" VALUES (2, 'BLUE');
INSERT INTO "PRACTICE_TEST"."COLOUR_HISTORY_TABLE" VALUES (3, 'RED');
COMMIT;
UPDATE"PRACTICE_TEST"."COLOUR_HISTORY_TABLE" MERGE DELTA INDEX;
Now let’s do a simple join to view the data in the two tables
SELECT M."KEY", C."HUE" FROM "PRACTICE_TEST"."MODEL_HISTORY_TABLE" M
JOIN "PRACTICE_TEST"."COLOUR_HISTORY_TABLE"
C ON M."VALUE" = C."VALUE";
The result for the above query, based on the data entered till now would be as follows:
Now let us make some updates in the records, so that the records will have some history of updates since the time they were created.
UPDATE "PRACTICE_TEST"."MODEL_HISTORY_TABLE" SET "VALUE" = 4 WHERE "KEY" = 'AA';
UPDATE "PRACTICE_TEST"."MODEL_HISTORY_TABLE" SET "VALUE" = 5 WHERE "KEY" = 'CC';
COMMIT;
UPDATE"PRACTICE_TEST"."MODEL_HISTORY_TABLE" MERGE DELTA INDEX;
There are a number of ways of using “Time Travel” queries. We can either track the historic values using the commit ID for the transactions, or by using the UTC time-stamping for the transactions, or by setting the session back to some earlier historic session.
For better understanding, just repeating what we have done so far. We created two History tables as follows:
Also, the below graphic shows the entire history of the updates made in both the tables, along with respective commit IDs and timestamp values.
The above representation is good for quick understanding in a demo purpose, but in real life, there are no such views available. For that, we need some alternate ways of getting all the required commit ID and the timestamps. Following section shows steps for doing that.
The entire list of all the commit IDs/Commit-time can be obtained using the following syntax:
SELECT * FROM TRANSACTION_HISTORY ORDERBY COMMIT_ID;
This results into the following list of commit IDs:
Note: In our case, the number of transaction were limited, so we have listed the Commit IDs for all the transactions made. In case this list is huge, the relevant commit IDs can be tracked by adding where clause in the above statement, as mentioned in following example:
SELECT * FROM TRANSACTION_HISTORY
WHERE COMMIT_ID >= 200610
ORDERBY COMMIT_ID;
Now the TIME TRAVEL queries can be executed, i.e. historical values can be retrieved in following possible ways:
Use the select statement with phrase ‘AS OF COMMIT ID’ to refer to some historical values of the history table.
The historical values of the table, when the tables were first committed (i.e. Commit ID= 200611) can be derived using the following syntax:
select * from "PRACTICE_TEST"."MODEL_HISTORY_TABLE"
AS OF COMMIT ID 200611
Until this commit ID, there was no data entered in the second table ("PRACTICE_TEST"."COLOUR_HISTORY_TABLE"), so doing a join operation between the two tables for this commit ID would result into NULL return.
SELECT M."KEY", C."HUE" FROM "PRACTICE_TEST"."MODEL_HISTORY_TABLE" M
JOIN "PRACTICE_TEST"."COLOUR_HISTORY_TABLE" C ON M."VALUE" = C."VALUE"
AS OF COMMIT ID 200611;
As expected, it was all blank result set, since at this commit ID, there is no data in the COLOUR_HISTORY_TABLE.
The output for the join between two tables will be available only after the instance since when both tables had some valid data, which is after the commit ID 200721. So repeating the same join query with this commit ID 200721 should fetch some valid results:
This way, simple (or bit complex) queries can be used to browse through historic data without having to actually load the old data, or keeping multiple copies of data in backup, saving enormous amount of storage space and efforts.
Alternatively, the time stamping information of transactions (called UTC timestamps) can also be used for browsing values in historic instances.
Using the select statement with phrase ‘AS OF UTCTIMESTAMP’ also refers to historical values of the history table based on the UTC time stamps made in the history table.
As already discussed, the UTC Timestamp can be identified from the sys.transaction_history table.
If specific commit ID is known, corresponding commit time can be identified using following syntax:
select commit_time from sys.transaction_history
where commit_id = 201039;
Output: '2013-02-04 12:01:42.682'
This timestamp can be used to refer to historical values of the tables using the following syntax:
SELECT M."KEY", C."HUE" FROM "PRACTICE_TEST"."MODEL_HISTORY_TABLE" M
JOIN "PRACTICE_TEST"."COLOUR_HISTORY_TABLE" C ON M."VALUE" = C."VALUE"
AS OF utctimestamp '2013-02-04 12:01:42.682';
Please note that at the commit ID 201039 (or time stamp value '2013-02-04 12:01:42.682'), the data in the first table (MODEL_HISTORY_TABLE) was already altered, and so now I has only one common value, which appears as the output of above join statement.
A database session can be set back to a certain point-in-time, based on the provided value for commit_id. For doing this SET HISTORY SESSION can be used.
SET HISTORY SESSIONTO COMMIT ID 201039;
SELECT M."KEY", C."HUE" FROM "PRACTICE_TEST"."MODEL_HISTORY_TABLE" M
JOIN "PRACTICE_TEST"."COLOUR_HISTORY_TABLE" C ON M."VALUE" = C."VALUE"
This would result in same output as above, since we are referring to the same instance of the database at exactly the same historic time as the above query.
By setting the HISTORY SESSION to a particular Commit ID, all subsequent queries will return data as of that Commit ID, until the command is cancelled by setting the history session to another value, or cancelling it by setting it to NOW.
SET HISTORY SESSION TO NOW;
In similarity to above method, the database session can be set back to a certain point-in-time, based on the provided value for UTC time stamp.
SET HISTORY SESSIONTO utctimestamp '2013-02-04 12:01:42.682';
SELECT M."KEY", C."HUE" FROM "PRACTICE_TEST"."MODEL_HISTORY_TABLE" M
JOIN "PRACTICE_TEST"."COLOUR_HISTORY_TABLE" C ON M."VALUE" = C."VALUE"
Again, we would get the same output. In a way, these (time travelling via using SELECT statement with commit ID, UTC Timestamps or by using SET HISTORY SESSION) are all different ways of reaching to the same results.
Important Notes:
[Source: http://help.sap.com/hana/html/sql_create_table_history_time_travel.html]
For demonstration purposes, implementing time travel seems to be bit easy task. But in real life scenarios, implementation would be much more complex, and would demand entire new set of plans and designs for fully utilizing this new concept.
We would love to hear more about real life scenarios where this concept could make a real difference. So do provide your feedback and suggestions about this topic.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
10 | |
9 | |
5 | |
4 | |
4 | |
3 | |
3 | |
3 | |
3 | |
3 |