Tag Archives: Performance
What’s New in OBIEE 11.1.1.9 for Systems Administrators and Developers
After over two years since the last major release of OBIEE, Oracle released version 11.1.1.9 in May 2015. You can find the installers here and documentation here. 11.1.1.9 is termed the “terminal release” of the 11g line, and the 12c version is already out in closed-beta. We’d expect to see patchsets for 11g to continue for some time covering bugs and any security issues, but for new functionality in 11g I would hazard a guess that this is pretty much it as Oracle concentrate their development efforts on OBIEE 12c and BICS, particularly Visual Analyser.
For both the end user and backend administrator/developer, OBIEE 11.1.1.9 has brought with it some nice little touches, none of which are going to revolutionise the OBIEE world but many of which are going to make life with the tool just that little bit smoother. In this article we take a look at what 11.1.1.9 brings for the sysadmin & developer.
BI Server Query Instrumentation and Usage Tracking
There are some notable developments here:
- Millisecond precision when logging events from the BI Server
- Usage Tracking now includes the physical query hash, which is what is also visible in the database, enabling end-to-end tracing
- User sessions can be tracked and summarised more precisely because session ID is now included in Usage Tracking.
- The execution of initialisation blocks is now also recorded, in a new Usage Tracking table called S_NQ_INITBLOCK.
Millisecond precision in BI Server logs
OBIEE 11.1.1.9 writes the nqquery.log with millisecond precision for both the timestamp of each entry, and also the summary timings for a query execution (at last!). It also calls out explicitly “Total time in BI Server” which is a welcome addition from a time profiling/performance analysis point of view:
[2016-07-31T02:11:48.231-04:00 [...] Sending query to database named X0 - Airlines Demo Dbs (ORCL) (id: <<221516>>), connection pool named Aggr Connection, logical request hash 544131ec, physical request hash 5018e5db: [[ [2016-07-31T02:12:04.31-04:00 [...] Query Status: Successful Completion [2016-07-31T02:12:04.31-04:00 [...] Rows 2, bytes 32 retrieved from database query id: <<221516>> [2016-07-31T02:12:04.31-04:00 [...] Physical query response time 2.394 (seconds), id <<221516>> [2016-07-31T02:12:04.31-04:00 [...] Physical Query Summary Stats: Number of physical queries 1, Cumulative time 2.394, DB-connect time 0.002 (seconds) [2016-07-31T02:12:04.31-04:00 [...] Rows returned to Client 2 [2016-07-31T02:12:04.31-04:00 [...] Logical Query Summary Stats: Elapsed time 16.564, Total time in BI Server 16.555, Response time 16.564, Compilation time 0.768 (seconds), Logical hash 544131ec
One thing to notice here is the subsecond timestamp precision seems to vary between 2 and 3 digits, which may or may not be a bug.
Being able to see this additional level of precision is really important. Previously OBIEE recorded information by the second, which was fine if you were looking at query executions taking dozens of seconds or minutes – but hopefully our aspirations for systems performance are actually closer to the realms of seconds or subsecond. At this scale the level of precision in the timings really matters. On the assumption that OBIEE was rounding values to the nearest whole number, you’d see “0 seconds” for a Logical SQL compile (for example) that was maybe 0.499 seconds. Per query this is not so significant, but if those queries run frequently then cumulatively that time stacks up and would be useful to be properly aware of and target with optimisation if needed.
Usage Tracking changes
Usage Tracking has five new columns for each logical query recorded in S_NQ_ACCT:
- ECID
- TENANT_ID
- SERVICE_NAME
- SESSION_ID
- HASH_ID
The presence of SESSION_ID is very useful, because it means that user behaviour can be more accurately analysed. For example, within a session, how many reports does a user run? What is the median duration of a session? Note that the session here is the session as seen by the BI Server, rather than Presentation Services.
ECID is also very useful for being able to link data in Usage Tracking back to more detailed entries in nqquery.log. Note that an ECID is multipart and concanated with RID and you won’t necessarily get a direct hit on the ECID you find in Usage Tracking with that in nqquery.log, but rather a substring of it. In this example here the root ECID is 11d1def534ea1be0:20f8da5c:14d4441f7e9:–8000–0000000000001891,0:1:103 and the varying component of the relationship (RID) id 1 and 3 respectively:
Usage Tracking:
select ecid,session_id,start_dt,start_hour_min ,saw_src_path from biee_biplatform.s_nq_acct
nqquery.log:
[2015-05-12T08:58:38.704-04:00] [...] [ecid: 11d1def534ea1be0:20f8da5c:14d4441f7e9:-8000-0000000000001891,0:1:103:3] [...] -------------------- SQL Request, logical request hash: 3fabea2b SET VARIABLE QUERY_SRC_CD='Report',SAW_DASHBOARD='/shared/02. Visualizations/_portal/2.11 Table Designs',SAW_DASHBOARD_PG='Conditional Format',SAW_SRC_PATH='/shared/02. Visualizations/Configured Visuals/Conditional Formats/CF based on a hidden column',PREFERRED_CURRENCY='USD';SELECT^M 0 s_0,^M [...]
In the above example note how the absence of a timezone in the Usage Tracking data is an impedance to accurate interpretation of the results, compared to nqquery.log which has a fully qualified timezone offset.
Usage Tracking changes – Physical Hash ID
As well as additions to the logical query table, there are two new columns for each physical query logged in S_NQ_DB_ACCT:
- HASH_ID
- PHYSICAL_HASH_ID
The implications of this are important – there is now native support in OBIEE for tracing OBIEE workloads directly down to the database (as discussed for OBIEE < 11.1.1.9 here), because the PHYSICAL_HASH_ID
is what OBIEE sets as the ACTION field when it connects to the database and is available in Oracle through both AWR, V$ views, and DBMS_MONITOR. For example, in V$SESSION the ACTION field is set to the physical hash:
SQL> select username,program,action from v$session where lower(program) like 'nqs%'; USERNAME PROGRAM ACTION -------- ------------------------------------------------ --------- BISAMPLE nqsserver@demo.us.oracle.com (TNS V1-V3) 5065e891 BISAMPLE nqsserver@demo.us.oracle.com (TNS V1-V3) 2b6148b2 BISAMPLE nqsserver@demo.us.oracle.com (TNS V1-V3) BISAMPLE nqsserver@demo.us.oracle.com (TNS V1-V3) 8802f14e BISAMPLE nqsserver@demo.us.oracle.com (TNS V1-V3) 206c8d54 BISAMPLE nqsserver@demo.us.oracle.com (TNS V1-V3) c1c121a7
The ACTION is also available in many EM screens such as this one:
Now with OBIEE 11.1.1.9 the physical hash – which was previously only available in the nqquery.log file – is available in S_NQ_DB_ACCT which can in turn be joined to S_NQ_ACCT to find out the logical request related to the physical query seen on the database. Cool huh!
SELECT PHYSICAL_HASH_ID, USER_NAME, SAW_SRC_PATH, SAW_DASHBOARD, SAW_DASHBOARD_PG FROM BIEE_BIPLATFORM.S_NQ_DB_ACCT PHYS INNER JOIN BIEE_BIPLATFORM.S_NQ_ACCT LOGL ON LOGL.ID = PHYS.LOGICAL_QUERY_ID WHERE PHYS.PHYSICAL_HASH_ID = '5065e891'
This can be extended even further to associate AWR workload reports with specific OBIEE requests:
One little grumble (no pleasing some people…) – it would have been nice if Usage Tracking also stored:
- Timings at millisecond precision as well
- The number of bytes (rather than just row count)
- A proper TIMESTAMP WITH TIME ZONE (rather than the weird triplet of TS/DT/HOUR_MIN)
- “Total time in BI Server”
Who knows, maybe in 12c?…
Footnote – START_TS in Usage Tracking in 11.1.1.9
As a note for others who may hit this issue, my testing has shown that Usage Tracking in 11.1.1.9 appears to have introduced a bug with START_TS (on both S_NQ_ACCT and S_NQ_DB_ACCT), in that it stores only the date, not date + time as it did in previous versions. For example:
- 11.1.1.7:
SELECT TO_CHAR(START_TS, 'YYYY-MM-DD HH24:MI:SS') AS START_TS, TO_CHAR(START_DT, 'YYYY-MM-DD HH24:MI:SS') AS START_DT, START_HOUR_MIN FROM S_NQ_ACCT WHERE ROWNUM < 2 START_TS START_DT START_HOUR_MIN ------------------- ------------------- ----- 2015-03-19 15:32:23 2015-03-19 00:00:00 15:32
- 11.1.1.9:
SELECT TO_CHAR(START_TS, 'YYYY-MM-DD HH24:MI:SS') AS START_TS, TO_CHAR(START_DT, 'YYYY-MM-DD HH24:MI:SS') AS START_DT, START_HOUR_MIN FROM S_NQ_ACCT WHERE ROWNUM < 2 START_TS START_DT START_HOUR_MIN ------------------- ------------------- ----- 2015-01-27 00:00:00 2015-01-27 00:00:00 10:41
Initialisation Block information in Usage Tracking
A new table, S_NQ_INITBLOCK, has been added to BIPLATFORM and holds details of when an init block ran, for which user, and importantly, how long it took. From a performance analysis point of view this is really valuable data and it’s good to seeing it being added to the diagnostic data captured to database with Usage Tracking.
From a glance at the data it looks like there’s a bit of a bonus logging going on, with user sign in/sign out also recorded (“SIGNNING ON/SIGNED ON/SIGNED OFF”).
Note that there is no MBean for Init Block Usage Tracking, so regardless of how you configure the rest of Usage Tracking, you need to go to NQSConfig.ini to enable this one.
Presentation Services Cursor Cache
Oracle have added some additional Administration functionality for viewing and managing sessions and the cursor cache in Presentation Services. These let you track and trace more precisely user sessions.
From the Administration Page in OBIEE the new options are:
- Set dynamic log level per session from manage sessions
-
Filter cursor cache based on specific user sessions
-
Change sort order of cursor cache
-
Show Presentation Services diagnostics per cursor
- Download cursor cache list as CSV
- I can see this being useful for integration into bespoke monitoring applications, to which I must profess an interest…
Some of these are somewhat low-level and will not be used day-to-day, but the general move towards a more open diagnostics interface with OBIEE is really positive and I hope we see more of it in 12c… :-)
Command Line Aggregate Advisor
Only for use by those with an Exalytics licence, the Summary Advisor was previously available in the Windows Administration Tool only but can now be run from the command line:
[oracle@demo setup]$ nqaggradvisor -h Usage: nQAggrAdvisor -d <dataSource> -u <userName> -o <outputFile> -c <tupleInQuotes> [-p <password>] [-F <factFilter>] [-z <maxSizeAggr>] [-g <gainThreshold>] [-l <minQueryTime>] [-t <timeoutMinutes>] [-s <startDate>] [-e <endDate>] [-C <on/off>] [-M <on/off>] [-K <on/off>] Options: -d : Data source name -u : User name -o : Output aggregate persistence script file name -c : Aggregate persistence target - tuple in quotes: Fully qualified Connection pool, fully qualified schema name, capacity in MB -p : Password -F : Fact filter file name -z : Max size of any single aggregate in MB -g : Summary advisor will run until performance improvement for new aggregates drops below this value, default = 1 -l : The minimum amount of query time accumulated per LTS in seconds, before it is included for analysis, default = 0 -t : Max run time in minutes - 0 for unlimited, default = 0 -s : Statistics start date -e : Statistics end date -C : Prefer optimizer estimates - on/off, default = off -M : Only include measures used in queries - on/off, default = off -K : Use surrogate keys - on/off, default = on Examples: nQAggrAdvisor -d "AnalyticsWeb" -u "Administrator" -p "ADMIN" -o "C:tempaggr_advisor.out.txt" -c "DW_Aggr"."Connection Pool","DW_Aggr".."AGGR",1000 nQAggrAdvisor -d "AnalyticsWeb" -u "Administrator" -p "ADMIN" -o "C:tempaggr_advisor.out.txt" -F "C:tempfact_filter.txt" -g 10 -c "TimesTen_instance1"."Connection Pool","dbo",2000 -s "2011-05-02 08:00:00" -e "2011-05-07 18:30:00" -C on -M on -K off
Note that in the BIPLATFORM schema S_NQ_SUMMARY_STATISTICS is now called S_NQ_SUMMARY_ADVISOR.
HTML5 images
In previous versions of OBIEE graph images were rendered in Flash by default, and PNG on mobile devices. You could force it to use PNG for all images but would loose the interactivity (tooltips etc). Now in OBIEE 11.1.1.9 you can change the default from Flash to HTML5. This removes the need for a Flash plugin and is generally the way that a lot of visualisations are done on the web nowadays. To my eye there’s no difference in appearance:
To use HTML5 graphs by default, edit instanceconfig.xml
and under <Charts>
section add:
<DefaultWebImageType>html5</DefaultWebImageType>
Note that html5
is case-sensitive. The config file should look something like this:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <WebConfig xmlns="oracle.bi.presentation.services/config/v1.1"> <ServerInstance> [...] <Views> [...] <Charts> <DefaultWebImageType>html5</DefaultWebImageType> [...] </Charts> [...] </Views> [...] </ServerInstance> </WebConfig>
If Presentation Services doesn’t come back up when you restart it after making this change then check the stdout
logfile console~coreapplication_obips1~1.log
as well as the standard sawlog.log file, both of which you’ll find in $FMW_HOME/instances/instance1/diagnostics/logs/OracleBIPresentationServicesComponent/
. The reason to check the console log file is that Presentation Services will refuse to start if the configuration supplied is invalid, and you’ll see an error message stating this here.
NQS ODBC functions
One for the Neos amongst you, a quick call of NQSGetSQLProcedures
(as seen in SampleApp dashboard 7.90 NQS ODBC Procedures) and comparison with 11.1.1.7.150120 shows the following new & changed NQS ODBC calls. If this means nothing to you then it probably doesn’t need to, but if you’re interested in exploiting OBIEE functionality from all angles, documented or not, then these might be of interest. It goes without saying, these are entirely undocumented and unsupported, completely liable to change or be removed at any time by Oracle.
- Added
- NQSGetUserDefinedFunctions
- NQSPAFIntegration
- NQSSearchPresentationObjects
- NQS_GetAllCacheEntries
- NQS_GetOverallCacheInfo
- NQS_GetRepositories
- NQS_LoadNewBaseRP
- NQS_LoadNewRPVersion
- NQS_LockSessionAgainstAutoRPSwitchOver
- NQS_SetRPDReadOnlyMode
- NQS_SwitchOverThisSessionToNewRP
- SAPurgeCacheBySubjectArea
- SAPurgeCacheEntryByIDVector
- SAPurgeXSACache
- SASeedXSACache
- Modified
- NQSGetQueryLogExcerpt (additional parameter)
- SAPurgeInternalCache (additional enum)
- Removed
- NQSChangeSelfPassword
Web Services
Web Services are one of the best ways to integrate with OBIEE programatically. You don’t need to be building heavy java apps just to use them – you can create and send the necessary SOAP messages from python or even just send it from bash with curl
.
There are 2.5 new WSDLs – two new ones (v9, v10) plus v8 which has changed. The new services are:
- KPIAssessmentService
- ScorecardAssessmentService
- ScorecardMetadataService
- UserPersonalizationService
You’ll find documentation for the Web Services in the Integrator’s Guide.
User Image Upload
Users can now upload their own images for use in Title views, conditional formats, etc. From an administration point of view this means you’ll want to be keeping an eye on /root/shared/custom/images/
in the Presentation Catalog, either on disk and/or through the OBIEE Catalog View, switch to Admin and enable “Show Hidden Items”:
QUERY_LIMIT_WARNING_INSTEAD_OF_ERROR
This new setting in NQSConfig.ini will warn users when they’re breaching defined query limits, but it won’t abort the query.
Pointless hacks
If you’re a geek like me, part of the fun of a new tool is simply poking around and seeing what’s new – not necessarily what’s useful. There’s plenty of great new stuff in 11.1.1.9, but let’s take a look at the “under the hood”, just Because Geek.
It was John Minkjan who first blogged several years about the xsd configuration schema files, and it is from this that we can find all the things that Presentation Services might be able to do – not just what it definitely can do, and not just what Oracle have documented that it can do. I wrote about some of these options a while back, and there are a few new ones in 11.1.1.9.
ALL OF THESE ARE COMPLETELY UNDOCUMENTED AND UNSUPPORTED. DO NOT USE THEM.
- EnableCloudBIEEHome sets the home page of OBIEE to be as it would be on BI Cloud Service (BICS). This is completely pointless since all the interesting stuff (Load Data, Model, Manage) is non-existent, even if it does give us a clue which application deployments are going to be supplying them (bimodeler and biserviceadministration respectively)
- GridViews/ShowDataModels outputs a bunch of debug data in Answers Table or Pivot Views:
- VirusScannerConfiguration – When a user uploads a custom image, this command will be called with it. For example, this simple script writes to a file the time and name of the file passed to it:
echo '---' >> /tmp/log.txt date >> /tmp/log.txt echo $1 >> /tmp/log.txt
If I save this as /tmp/test-script.sh and add it to instanceconfig.xml:
<VirusScannerConfiguration> <ScannerInvocationCommandLine>/tmp/test-script.sh</ScannerInvocationCommandLine> </VirusScannerConfiguration>
When I upload an image I get a row written to my log file. That in itself isn’t useful, but it could be a handy hook maybe from an auditing point of view, or indeed, virus scanning:
[oracle@demo tmp]$ cat /tmp/log.txt --- Wed May 20 16:01:47 EDT 2015 /app/oracle/biee/instances/instance1/tmp/OracleBIPresentationServicesComponent/coreapplication_obips1/defaultpool/sawserver_8673_5553759a_2-1.tmp
Analysing ODI performance with Flame Graphs
Flame Graphs are a visualisation that I learnt about through the excellent Linux systems performance work of Brendan Gregg, and saw Luca Canali talk about recently at UKOUG Tech 14. They’re a brilliant way of summarising extremely dense information in a way from which the main components accounting for the most time can be identified. I was recently doing some analysis for a client on their ODI batch runtime and I thought it would be a good idea to try them out. Load Plans can have complex hierarchies to them and working out which main sections account for what time can be tricky, as can following a load plan step through to a session and on to a session step and its constituent parts.
A flame graph is made up of the “stack trace” on the y-axis, and the amount of time spent in each on the x-axis. This is different from most other standard visualisations where the x-axis represents the passage of time, and instead summarises the data at multiple levels of the stack trace hierarchy. The “stack trace” in this case with ODI is Load plan -> load plan step (load plan step […]) -> session -> session step -> task. It’s as easy to see the overall run time as it is a load plan step part way down, as a constituent task of a session step. And what’s more, flame graphs look nice! This may seem a flimsy reason for using them on their own, but it’s a bonus over trawling through dull tables of data alone.
Looking at the flame graph above (taken from a demo BI Apps implementation) it’s nice and easy to see that the Warehouse Load Phase accounts for c.75% of the time, within which the two areas accounting for most time are AP and AR balances. This is from literally a single glance at one graphic. Flame Graphs are built as SVGs which enables them to be interactive (here’s an example). Clicking on any of the stack trace boxes drills into that area, so for the tasks taking less time (and so displaying less text) this is useful to see the specifics. Here’s the GL balance load in detail, showing how long the row inserts take in proportion to the index build:
Creating the flame graph is simple. You just need a stack trace that is semi-colon separated, followed by a space-delimited counter value at the end. A bit of recursive SQL magic with the SNP_ tables (helpfully documented by Oracle here) gives us this kind of output file with one line for every task executed and its duration:
;Start_Load_Plan;Global_Variable_Refresh;Source_Extract_Phase;1_General;2_General_PRE-SDE;3_PRE-SDE_Day;Finalize_Day;Finalize_W_DAY_D;CREATE_INDEXES;Create_Indexes_:_W_DAY_D_2/2;EXEC_TABLE_MAINT_PROC;TABLE_MAINT_PROC;Create Indexes 3 [...]
which you then run through the Flame Graph tool:
cat /tmp/odi.out |~/git/FlameGraph/flamegraph.pl --title "EBSVISION FIN HR_21_20141021_223159 / 2014-10-24 15:41:42" > /tmp/odi-flame-graph.svg
Simply load the resulting SVG into a web browser such as Chrome, and you’re done. Here’s an example that you can download and try out.
Instrumenting OBIEE Database Connections For Improved Performance Diagnostics
Nearly four years ago I wrote a blog post entitled “Instrumenting OBIEE – The Final Chapter”. With hindsight, that title suffix (“The Final Chapter”) may have been a tad presumptuous and naïve of me (or perhaps I can just pretend to be ironic now and go for a five-part-trilogy style approach…). Back then OBIEE 11g had only just been released (who remembers 11.1.1.3 in all its buggy-glory?), and in the subsequent years we’ve had significant patchset releases of OBIEE 11g bringing us up to 11.1.1.7.150120 now and with talk of OBIEE 12c around the corner.
As a fanboi of Cary Millsap and his approach to measuring and improving performance, instrumenting code in general – and OBIEE specifically – is something that’s interested me for a long time. The article was the final one that I wrote on my personal blog before joining Rittman Mead and it’s one that I’ve been meaning to re-publish here for a while. A recent client engagement gave me cause to revisit the instrumentation approach and refine it slightly as well as update it for a significant change made in OBIEE 11.1.1.7.1.
What do I mean by instrumentation? Instrumentation is making your program expose information about what is being done, as well as actually doing it. Crudely put, it’s something like this:
10 PRINT "THE TIME IS " NOW() 20 CALL DO_MY_THING() 30 PRINT "I'VE DONE THAT THING, IT TOOK " X " SECONDS" 40 GOTO 10
Rather than just firing some SQL at the database, instead we associate with that SQL information about what program sent it, and what that program was doing, who was using it, and so on. Instrumentation enables you to start analysing performance metrics against tangible actions rather than just amorphous clumps of SQL. It enables you to understand the workload profile on your system and how that’s affecting end users.
Pop quiz: which of these is going to be easier to work with for building up an understanding of a system’s behaviour and workload?
CLIENT_INFO MODULE ACTION CPU_TIME DISK_READS -------------------- ------------------------ ---------- ---------- ---------- a17ff8e1 2999 1 fe6abd92 1000 6 a264593a 5999 2 571fe814 5000 12 63ea4181 7998 4 7b2fcb68 11999 5
or
CLIENT_INFO MODULE ACTION CPU_TIME DISK_READS -------------------- ------------------------ ---------- ---------- ---------- 06 Column Selector GCBC Dashboard/Performan a17ff8e1 2999 1 05 Table with condit GCBC Dashboard/Performan a264593a 5999 2 06 View Selector GCBC Dashboard/Performan 571fe814 5000 12 05 Table with condit GCBC Dashboard/Performan 63ea4181 7998 4 <unsaved analysis> nqsserver@obi11-01 fe6abd92 1000 6 <unsaved analysis> nqsserver@obi11-01 7b2fcb68 11999 5
The second one gives us the same information as before, plus the analysis being run by OBIEE, and the dashboard and page.
The benefits of instrumentation work both ways. It makes DBAs happy because they can look at resource usage on the database and trace it back easily to the originating OBIEE dashboard and user. Instrumentation also makes life much easier for troubleshooting OBIEE performance because it’s easy to trace a user’s entire session through from browser, through the BI Stack, and down into the database.
Instrumentation for OBIEE – Step By Step
If you want the ‘tl;dr’ version, the “how” rather than the “why”, here we go. For full details of why it works, see later in the article.
- In your RPD create three session variables. These are going to be the default values for variables that we’re going to send to the database. Make sure you set “Enable any user to set the value”.
- SAW_SRC_PATH
- SAW_DASHBOARD
- SAW_DASHBOARD_PG
- Set up a session variable initialization block to populate these variables. It is just a “dummy” init block as all you’re doing is setting them to empty/default values, so a ‘SELECT … FROM DUAL’ is just fine:
- For each Connection Pool you want to instrument, go to the Connection Scripts tab and add these three scripts to the Execute before query section:
-- Pass the OBIEE user's name to CLIENT_IDENTIFIER call dbms_session.set_identifier('VALUEOF(NQ_SESSION.USER)')
-- Pass the Analysis name to CLIENT_INFO call dbms_application_info.set_client_info(client_info=>SUBSTR('VALUEOF(NQ_SESSION.SAW_SRC_PATH)',(LENGTH('VALUEOF(NQ_SESSION.SAW_SRC_PATH)')-instr('VALUEOF(NQ_SESSION.SAW_SRC_PATH)','/',-1,1))*-1))
-- Pass the dashboard name & page to MODULE -- NB OBIEE >=11.1.1.7.131017 will set ACTION itself so there is no point setting it here (it will get overridden) call dbms_application_info.set_module(module_name=> SUBSTR('VALUEOF(NQ_SESSION.SAW_DASHBOARD)', ( LENGTH('VALUEOF(NQ_SESSION.SAW_DASHBOARD)') - INSTR('VALUEOF(NQ_SESSION.SAW_DASHBOARD)', '/', -1, 1) ) *- 1) || '/' || 'VALUEOF(NQ_SESSION.SAW_DASHBOARD_PG)' ,action_name=> '' );
You can leave the comments in there, and in fact I’d recommend doing so to make it clear for future RPD developers what these scripts are for.
Your connection pool should look like this:
An important point to note is that you generally should not be adding these scripts to connection pools that are used for executing initialisation blocks. Initialisation block queries won’t have these request variables so if you did want to instrument them you’d need to find something else to include in the instrumentation.
Once you’ve made the above changes you should see MODULE, CLIENT_IDENTIFIER and CLIENT_INFO being populated in the Oracle system views :
SELECT SID, PROGRAM, CLIENT_IDENTIFIER, CLIENT_INFO, MODULE, ACTION FROM V$SESSION WHERE LOWER(PROGRAM) LIKE 'nqsserver%';
SID PROGRAM CLIENT_ CLIENT_INFO MODULE ACTION --- ------- ------- ------------------------ ---------------------------- -------- 17 nqsserv prodney Geographical Analysis 2 11.10 Flights Delay/Overview 32846912 65 nqsserv prodney Delayed Fligth % history 11.10 Flights Delay/Overview 4bc2a368 74 nqsserv prodney Delayed Fligth % history 11.10 Flights Delay/Overview 35c9af67 193 nqsserv prodney Geographical Analysis 2 11.10 Flights Delay/Overview 10bdad6c 302 nqsserv prodney Geographical Analysis 1 11.10 Flights Delay/Overview 3a39d178 308 nqsserv prodney Delayed Fligth % history 11.10 Flights Delay/Overview 1fad81e0 421 nqsserv prodney Geographical Analysis 2 11.10 Flights Delay/Overview 4e5d36c1
You’ll note that we don’t set ACTION – that’s because OBIEE now sends a hash of the physical query text across in this column, meaning we can’t use it ourselves. Unfortunately the current version of OBIEE doesn’t store the physical query hash anywhere other than in nqquery.log, meaning that you can’t take advantage of it (i.e. link it back to data from Usage Tracking) within the database alone.
That’s all there is to it – easy! If you want to understand exactly how and why it works, read on…
Instrumentation for OBIEE – How Does it Work?
Connection Pools
When OBIEE runs a dashboard, it does so by taking each analysis on that dashboard and sending a Logical Request for that analysis to the BI Server (nqsserver). The BI Server parses and compiles that Logical request into one or more Physical requests which it then sends to the source database(s).
OBIEE connects to the database via a Connection Pool which specifies the database-specific connection information including credentials, data source name (such as TNS for Oracle). The Connection Pool, as the name suggests, pools connections so that OBIEE is not going through the overhead of connecting and disconnecting for every single query that it needs to run. Instead it will open one or more connections as needed, and share that connection between queries as needed.
As well as the obvious configuration options in a connection pool such as database credentials, OBIEE also supports the option to send additional SQL to the database when it opens a connection and/or sends a new query. It’s this nice functionality that we piggy-back to enable our instrumentation.
Variables
The information that OBIEE can send back through its database connection is limited by what we can expose in variables. From the BI Server’s point of view there are three types of variables:
- Repository
- Session
- Request
The first two are fairly simple concepts; they’re defined within the RPD and populated with Initialisation Blocks (often known as “init blocks”) that are run by the BI Server either on a schedule (repository variables) or per user (session variables). There’s a special type of session variables known as System Session Variables, of which USER is a nice obvious example. These variables are pre-defined in OBIEE and are generally populated automatically when the user session begins (although some, like LOGLEVEL, still need an init block to set them explicitly).
The third type of variable, request variable, is slightly less obvious in function. In a nutshell, they are variables that are specified in the logical request sent to the BI Server, and are passed through to the internals of the BI Server. They’re often used for activating or disabling certain functionality. For example, you can tell OBIEE to specifically not use its cache for a request (even if it finds a match) by setting the request variable DISABLE_CACHE_HIT.
Request variables can be set manually inline in an analysis from the Advanced tab:
And they can also be set from Variable Prompts either within a report prompt or as a standalone dashboard prompt object. The point about request variables is that they are freeform; if they specify the name of an existing session variable then they will override it (if permitted), but they do not require the session variable to exist. We can see this easily enough – and see a variable request prompt in action at the same time. From the Prompts tab of an analysis I’ve added a Variable Prompt (rather than the usual Column Prompt) and given it a made up name, FOO:
Now when I run the analysis I specify a value for it:
and in the query log there’s the request variable:
-------------------- SQL Request, logical request hash: bfb12eb6 SET VARIABLE FOO='BAR'; SELECT 0 s_0, "A - Sample Sales"."Base Facts"."1- Revenue" s_1 FROM "A - Sample Sales" ORDER BY 1 FETCH FIRST 5000001 ROWS ONLY
I’ve cut the quoted Logical SQL down to illustrate the point about the variable, because what was actually there is this:
-------------------- SQL Request, logical request hash: bfb12eb6 SET VARIABLE QUERY_SRC_CD='Report',SAW_SRC_PATH='/users/prodney/request variable example',FOO='BAR', PREFERRED_CURRENCY='USD'; SELECT 0 s_0, "A - Sample Sales"."Base Facts"."1- Revenue" s_1 FROM "A - Sample Sales" ORDER BY 1 FETCH FIRST 5000001 ROWS ONLY
which brings me on very nicely to the key point here. When Presentation Services sends a query to the BI Server it does so with a bunch of request variables set, including QUERY_SRC_CD and SAW_SRC_PATH. If you’ve worked with OBIEE for a while then you’ll recognise these names – they’re present in the Usage Tracking table S_NQ_ACCT. Ever wondered how OBIEE knows what values to store in Usage Tracking? Now you know. It’s whatever Presentation Services tells it to. You can easily test this yourself by playing around in nqcmd
:
[oracle@demo ~]$ rlwrap nqcmd -d AnalyticsWeb -u prodney -p Admin123 -NoFetch ------------------------------------------------------------------------------- Oracle BI ODBC Client Copyright (c) 1997-2013 Oracle Corporation, All rights reserved ------------------------------------------------------------------------------- [...] Give SQL Statement: SET VARIABLE QUERY_SRC_CD='FOO',SAW_SRC_PATH='BAR';SELECT 0 s_0 FROM "A - Sample Sales" SET VARIABLE QUERY_SRC_CD='FOO',SAW_SRC_PATH='BAR';SELECT 0 s_0 FROM "A - Sample Sales" Statement execute succeeded
and looking at the results in S_NQ_ACCT:
BIEE_BIPLATFORM@pdborcl > select to_char(start_ts,'YYYY-MM-DD HH24:MI:SS') as start_ts,saw_src_path,query_src_cd from biee_biplatform.s_nq_acct where start_ts > sysdate -1 order by start_ts; START_TS SAW_SRC_PATH QUERY_SRC_CD ------------------- ---------------------------------------- -------------------- 2015-03-21 11:55:10 /users/prodney/request variable example Report 2015-03-21 12:44:41 BAR FOO 2015-03-21 12:45:26 BAR FOO 2015-03-21 12:45:28 BAR FOO 2015-03-21 12:46:23 BAR FOO
Key takeaway here: Presentation Services defines a bunch of useful request variables when it sends Logical SQL to the BI Server:
- QUERY_SRC_CD
- SAW_SRC_PATH
- SAW_DASHBOARD
- SAW_DASHBOARD_PG
Embedding Variables in Connection Script Calls
There are four options that we can configure when connecting to the database from OBIEE. These are:
- CLIENT_IDENTIFIER
- CLIENT_INFO
- MODULE
- ACTION
As of OBIEE version 11.1.1.7.1 (i.e. OBIEE >= 11.1.1.7.131017) OBIEE automatically sets the ACTION field to a hash of the physical query – for more information see Doc ID 1941378.1. That leaves us with three remaining fields (since OBIEE sets ACTION after anything we do with the Connection Pool):
- CLIENT_IDENTIFIER
- CLIENT_INFO
- MODULE
The syntax of the command in a Connection Script is physical SQL and the VALUEOF function to extract the OBIEE variable:
- VALUEOF(REPOSITORY_VARIABLE)
- VALUEOF(NQ_SESSION.SESSION_VAR)
- VALUEOF(NQ_SESSION.REQUEST_VAR)
As a simple example here is passing the userid of the OBIEE user, using the Execute before query connection script:
-- Pass the OBIEE user's name to CLIENT_IDENTIFIER call dbms_session.set_identifier('VALUEOF(NQ_SESSION.USER)')
This would be set for every Connection Pool – but only those used for query execution – not init blocks. Run a query that is routed through the Connection Pool you defined the script against and check out V$SESSION:
SQL> select sid,program,client_identifier from v$session where program like 'nqsserver%'; SID PROGRAM CLIENT_IDENTIFIER ---------- ------------------------------------------------ ---------------------------------------------------------------- 22 nqsserver@demo.us.oracle.com (TNS V1-V3) prodney
The USER session variable is always present, so this is a safe thing to do. But, what about SAW_SRC_PATH? This is the path in the Presentation Catalog of the analysis being executed. Let’s add this into the Connection Pool script, passing it through as the CLIENT_INFO:
-- Pass the Analysis name to CLIENT_INFO call dbms_application_info.set_client_info(client_info=>'VALUEOF(NQ_SESSION.SAW_SRC_PATH)')
This works just fine for analyses within a dashboard, or standalone analyses that have been saved. But what about a new analysis that hasn’t been saved yet? Unfortunately the result is not pretty:
[10058][State: S1000] [NQODBC] [SQL_STATE: S1000] [nQSError: 10058] A general error has occurred. [nQSError: 43113] Message returned from OBIS. [nQSError: 43119] Query Failed: [nQSError: 23006] The session variable, NQ_SESSION.SAW_SRC_PATH, has no value definition. Statement execute failed
That’s because SAW_SRC_PATH is a request variable and since the analysis has not been saved Presentation Services does not pass it to BI Server as a request variable. The same holds true for SAW_DASHBOARD and SAW_DASHBOARD_PG if you run an analysis outside of a dashboard – the respective request variables are not set and hence the connection pool script causes the query itself to fail.
The way around this is we cheat, slightly. If you create a session variable with the names of these request variables that we want to use in the connection pool scripts then we avoid the above nasty failures. If the request variables are set then all is well, and if they are not then we fall back on whatever value we initialise the session variable with.
The final icing on the cake of the solution given above is a bit of string munging with INSTR
and SUBSTR
to convert and concatenate the dashboard path and page into a single string, so instead of :
/shared/01. QuickStart/_portal/1.30 Quickstart/Overview
we get:
1.30 Quickstart/Overview
Which is much easier on the eye when looking at dashboard names. Similarly with the analysis path we strip all but the last section of it.
Granular monitoring of OBIEE on the database
Once OBIEE has been configured to be more articulate in its connection to the database, it enables the use of DBMS_MONITOR to understand more about the performance of given dashboards, analyses, or queries for a given user. Through DBMS_MONITOR the collection of statistics such as DB time, DB CPU, and so can be triggered, as well as trace-file generation for queries matching the criteria specified.
As an example, here is switching on system statistics collection for just one dashboard in OBIEE, using SERV_MOD_ACT_STAT_ENABLE
call dbms_monitor.SERV_MOD_ACT_STAT_ENABLE( module_name=>'GCBC Dashboard/Overview' ,service_name=>'orcl' );
Now Oracle stats to collect information whenever that particular dashboard is run, which we can use to understand more about how it is performing from a database point of view:
SYS@orcl AS SYSDBA> select module,stat_name,value from V$SERV_MOD_ACT_STATS; MODULE STAT_NAME VALUE ------------------------ ------------------------------ ---------- GCBC Dashboard/Overview user calls 60 GCBC Dashboard/Overview DB time 6789 GCBC Dashboard/Overview DB CPU 9996 GCBC Dashboard/Overview parse count (total) 15 GCBC Dashboard/Overview parse time elapsed 476 GCBC Dashboard/Overview execute count 15 GCBC Dashboard/Overview sql execute elapsed time 3887 [...]
Similarly the CLIENT_IDENTIFIER field can be used to collect statistics with CLIENT_ID_STAT_ENABLE or trigger trace file generation with CLIENT_ID_TRACE_ENABLE. What you populate CLIENT_IDENTIFIER with it up to you – by default the script I’ve detailed at the top of this article inserts the OBIEE username in it, but you may want to put the analysis here if that’s of more use from a diagnostics point of view on the database side. The CLIENT_INFO field is still available for the other item, but cannot be used with DBMS_MONITOR for identifying queries.
Display charts as images without using Flash
To display charts as images without using Flash, change the default image type to non-flash. Follow these steps;
- go to the directory of instanceconfig.xml
cd $ORACLE_INSTANCE/config/OracleBIPresentationServicesComponent/coreapplication_obips1
- make a copy of instanceconfig.xml
-
cp instanceconfig.xml instanceconfig.xml[_orig]
- edit instanceconfig.xml
vi instanceconfig.xml
- between </Table> and </Views> insert the tag
<Charts> <DefaultWebImageType>png</DefaultWebImageType> </Charts>
- be sure that png is lowercase, because when it is not, the presentation server will not start after restart!
- a part of the instanceconfig.xml must look like this now;
</Table> <Charts> <DefaultWebImageType>png</DefaultWebImageType> </Charts> </Views>
- save and quit
:wq
Note; some reports may have a hardcoded rendering type flash. To be sure every report is working with the rendering type specified within the instanceconfig, change the “renderFormat” within the XML of the reports, by following these steps;
- open Catalog Manager
- open the online catalog
- go to the directory or report
- select the XML Search and Replace
- change renderFormat=”flash” to renderFormat=”default”
- log in to Enterprise Manager
- click Business Intelligence - coreapplication
- click Availability
- click Processes
- click Restart All
- wait untill the Done message appears
Het bericht Display charts as images without using Flash verscheen eerst op OBIEE 24/7.
An Introduction to Analysing ODI Runtime Data Through Elasticsearch and Kibana 4
An important part of working with ODI is analysing the performance when it runs, and identifying steps that might be inefficient as well as variations in runtime against a baseline trend. The Operator tool in ODI itself is great for digging down into individual sessions and load plan executions, but for broader analysis we need a different approach. We also need to make sure we keep the data available for trend analysis, as it’s often the case that tables behind Operator are frequently purged for performance reasons.
In this article I’m going to show how we can make use of a generic method of pulling information out of an RDBMS such as Oracle and storing it in Elasticsearch, from where it can be explored and analysed through Kibana. It’s standalone, it’s easy to do, it’s free open source – and it looks and works great! Here I’m going to use it for supporting the analysis of ODI runtime information, but it is equally applicable to any time-based data you’ve got in an RDBMS (e.g. OBIEE Usage Tracking data).
Kibana is an open-source data visualisation and analysis tool, working with data stored in Elasticsearch. These tools work really well for very rapid analysis of any kind of data that you want to chuck at them quickly and work with. By skipping the process of schema definition and data modelling the time taken to the first results is drastically reduced. It enables to you quickly start “chucking about” data and getting meaning out of it before you commit full-scale to how you want to analyse it, which is what the traditional modelling route can sometimes force you to do prematurely.
ODI writes runtime information to the database, about sessions run, steps executed, time taken and rows processed. This data is important for analysing things like performance issues, and batch run times. Whilst with the equivalent runtime data (Usage Tracking) from OBIEE there is the superb RPD/Dashboard content that Oracle ship in SampleApp v406, for ODI the options aren’t as vast, ultimately being based on home-brew SQL against the repository tables using the repository schema documentation from Oracle. Building an OBIEE metadata model against the ODI schema is one option, but then requires an OBIEE server on which to run it – or merging into an existing OBIEE deployment – which means that it can become more hassle than it’s worth. It also means a bunch of up-front modelling before you get any kind of visualisations and data out. By copying the data across into Elasticsearch it’s easy to quickly build analyses against it, and has the additional benefit of retaining the data as long as you’d like meaning that it’s still available for long-term trend analysis once the data’s been purged from the ODI repository itself.
Let’s take a bit of a walk through the ODI dashboard that I’ve put together. First up is a view on the number of sessions that have run over time, along with their duration. For duration I’ve shown 50th (median), 75th and 95th percentiles to get an idea of the spread of session runtimes. At the moment we’re looking at all sessions, so it’s not surprising that there is a wide range since there’ll always be small sessions and longer ones:
Next up on the dashboard comes a summary of top sessions by runtime, both cumulative and per-session. The longest running sessions are an obvious point of interest, but cumulative runtime is also important; something may only take a short while to run when compared to some singular long-running sessions, but if it runs hundreds of times then it all adds up and can give a big performance boost if time is shaved off it.
Plotting out session execution times is useful to be able to see both when the longest running sessions ran:
The final element on this first dashboard is one giving the detail for each of the top x long-running session executions, including the session number so that it can be examined in further detail through the Operator tool.
Kibana dashboards are interactive, so you can click on a point in a graph to zoom in on that time period, as well as click & drag to select an arbitrary range. The latter technique is sometimes known as “Brushing”, and if I’m not describing it very well have a look at this example here and you’ll see in an instant what I mean.
As you focus on a time period in one graph the whole dashboard’s time filter changes, so where you have a table of detail data it then just shows it for the range you’ve selected. Notice also that the granularity of the aggregation changes as well, from a summary of every three hours in the first of the screenshots through to 30 seconds in the last. This is a nice way of presenting a summary of data, but isn’t always desirable (it can mask extremes and abnormalities) so can be configured to be fixed as well.
Time isn’t the only interaction on the dashboard – anything that’s not a metric can be clicked on to apply a filter. So in the above example where the top session by cumulative time are listed out we might want to find out more about the one with several thousand executions
Simply clicking on it then filters the dashboard and now the session details table and graph show information just for that session, including duration, and rows processed:
Session performance analysis
As an example of the benefit of using a spread of percentiles we can see here is a particular session that had an erratic runtime with great variation, that then stabilised. The purple line is the 95th percentile response time; the green and blue are 50th and 75th respectively. It’s clear that whilst up to 75% of the sessions completed in about the same kind of time each time they ran, the remaining quarter took anything up to five times as long.
One of the most important things in performance is ensuring consistent performance, and that is what happens here from about half way along the horizontal axis at c.February:
But what was causing the variation? By digging a notch deeper and looking at the runtime of the individual steps within the given session it can be seen that the inconsistent runtime was caused by a single step (the green line in this graph) within the execution. When this step’s runtime stabilises, so does the overall performance of the session:
This is performing a port-mortem on a resolved performance problem to illustrate how useful the data is – obviously if there were still a performance problem we’d have a clear path of investigation to pursue thanks to this data.
If you’re interested in how to put together this kind of dashboard in Kibana and Elasticsearch, loading in data on a regular basis from an RDBMS, then stay tuned for part 2 when all will be revealed…