SlideShare a Scribd company logo
1 of 25
Download to read offline
Profiling Mondrian MDX Requests
in a Production Environment
Raimonds Simanovskis
@rsim
Make All Mondrian MDX Requests
Super Fast in a Production Environment
What Takes So Long Time When
Mondrian MDX Requests Are Slow?
Summary of eazyBI
Technology stack
eazybi.com github.com/rsim/mondrian-olap
github.com/rsim/mondrian_udf
Mondrian
Single JVM process
Big Monolithic Application
Multi-tenant web application
mondrian-olap JRuby library
Mondrian
Schema and
segment cache
DB schema 1
Dimension4Dimension3
Dimension2Dimension1
Measure
DB schema 2
Dimension4Dimension3
Dimension2Dimension1
Measure
DB schema 10 000
Dimension4Dimension3
Dimension2Dimension1
Measure
DB schema 10 001
Dimension4Dimension3
Dimension2Dimension1
Measure
… …
Production JVM monitoring
Failing MDX requests logging
Top slow reports
Black Mondrian Magic
Mondrian
Schema
and
segment
cache
DB schema
Dimension4Dimension3
Dimension2Dimension1
Measure
SELECT {[Measures].[Store Sales],
[Measures].[Store Cost],
[Measures].[Unit Sales] } ON COLUMNS,
[Customers].[State Province].Members ON ROWS
FROM [Sales]
select `d_customers`.`country` as `c0`, `d_customers`.`state_province` as `c1`
from `eazybi_development_dwh_20`.`d_customers` as `d_customers`
group by `d_customers`.`country`, `d_customers`.`state_province`
order by ISNULL(`d_customers`.`country`) ASC, `d_customers`.`country` ASC,
ISNULL(`d_customers`.`state_province`) ASC, `d_customers`.`state_province` ASC
select `d_customers`.`country` as `c0`, `d_customers`.`state_province` as `c1`,
sum(`sales`.`store_sales`) as `m0`, sum(`sales`.`store_cost`) as `m1`,
sum(`sales`.`unit_sales`) as `m2`
from `eazybi_development_dwh_20`.`d_customers` as `d_customers`, `eazybi_development_dwh_20`.`sales` as `sales`
where `sales`.`customer_id` = `d_customers`.`id` and `d_customers`.`country` = 'USA'
group by `d_customers`.`country`, `d_customers`.`state_province`
Debugging in development
log4j.rootLogger=DEBUG, MONDRIAN
log4j.appender.MONDRIAN=org.apache.log4j.ConsoleAppender
log4j.appender.MONDRIAN.layout=org.apache.log4j.PatternLayout
log4j.appender.MONDRIAN.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss Z} %-5p [%c] %m%n
log4j.category.mondrian.mdx=DEBUG, MONDRIAN
log4j.category.mondrian.sql=DEBUG, MONDRIAN
Debugging in development
2018-11-22 16:32:02 +0000 DEBUG [mondrian.mdx] 308: select {[Measures].[Store Sales], [Measures].
[Store Cost], [Measures].[Unit Sales]} ON COLUMNS,
[Customers].[State Province].Members ON ROWS
from [Sales]
2018-11-22 16:32:02 +0000 DEBUG [mondrian.sql] 7: SqlTupleReader.readTuples [[Customers].[State
Province]]: executing sql [select `d_customers`.`country` as `c0`, `d_customers`.`state_province` as
`c1` from `eazybi_development_dwh_20`.`d_customers` as `d_customers` group by `d_customers`.`country`,
`d_customers`.`state_province` order by ISNULL(`d_customers`.`country`) ASC, `d_customers`.`country`
ASC, ISNULL(`d_customers`.`state_province`) ASC, `d_customers`.`state_province` ASC]
2018-11-22 16:32:02 +0000 DEBUG [mondrian.sql] 7: , exec 0 ms
2018-11-22 16:32:02 +0000 DEBUG [mondrian.sql] 7: , exec+fetch 3 ms, 3 rows
2018-11-22 16:32:02 +0000 DEBUG [mondrian.sql] 8: Segment.load: executing sql [select
`d_customers`.`country` as `c0`, `d_customers`.`state_province` as `c1`, sum(`sales`.`store_sales`) as
`m0`, sum(`sales`.`store_cost`) as `m1`, sum(`sales`.`unit_sales`) as `m2` from
`eazybi_development_dwh_20`.`d_customers` as `d_customers`, `eazybi_development_dwh_20`.`sales` as
`sales` where `sales`.`customer_id` = `d_customers`.`id` and `d_customers`.`country` = 'USA' group by
`d_customers`.`country`, `d_customers`.`state_province`]
2018-11-22 16:32:02 +0000 DEBUG [mondrian.sql] 8: , exec 0 ms
2018-11-22 16:32:02 +0000 DEBUG [mondrian.sql] 8: , exec+fetch 7 ms, 3 rows
2018-11-22 16:32:02 +0000 DEBUG [mondrian.mdx] 308: exec: 68 ms
Query Timing and Profiling
/**
* Provides hooks for recording timing information of components of Query
* execution.
*
* <p>NOTE: This class is experimental and subject to change/removal
* without notice.
*
* <p>Code that executes as part of a Query can call
* {@link QueryTiming#markStart(String)}
* before executing, and {@link QueryTiming#markEnd(String)} afterwards, or can
* track execution times manually and call
* {@link QueryTiming#markFull(String, long)}.
*
* <p>To read timing information, add a handler to the statement using
* {@link mondrian.server.Statement#enableProfiling} and implement the
* {@link mondrian.spi.ProfileHandler#explain(String, QueryTiming)} method.
*
* @author jbarnett
*/
public class QueryTiming {
Query Timing and Profiling
/**
* Provides hooks for recording timing information of components of Query
* execution.
*
* <p>NOTE: This class is experimental and subject to change/removal
* without notice.
*
* <p>Code that executes as part of a Query can call
* {@link QueryTiming#markStart(String)}
* before executing, and {@link QueryTiming#markEnd(String)} afterwards, or can
* track execution times manually and call
* {@link QueryTiming#markFull(String, long)}.
*
* <p>To read timing information, add a handler to the statement using
* {@link mondrian.server.Statement#enableProfiling} and implement the
* {@link mondrian.spi.ProfileHandler#explain(String, QueryTiming)} method.
*
* @author jbarnett
*/
public class QueryTiming {
mondrian-olap query profiling
result = connection.execute(
"SELECT {[Measures].[Store Sales], [Measures].[Store Cost], [Measures].[Unit Sales]} ON COLUMNS " 
"[Customers].[State Province].Members ON ROWS " 
"FROM [Sales]",
profiling: true
)
Axis (COLUMNS):
SetListCalc(name=SetListCalc, class=class mondrian.olap.fun.SetFunDef$SetListCalc, type=SetType<MemberType<member=[Measures].[Store
Sales]>>, resultStyle=MUTABLE_LIST)
2(name=2, class=class mondrian.olap.fun.SetFunDef$SetListCalc$2, type=MemberType<member=[Measures].[Store Sales]>, resultStyle=VALUE)
Literal(name=Literal, class=class mondrian.calc.impl.ConstantCalc, type=MemberType<member=[Measures].[Store Sales]>,
resultStyle=VALUE_NOT_NULL, value=[Measures].[Store Sales])
2(name=2, class=class mondrian.olap.fun.SetFunDef$SetListCalc$2, type=MemberType<member=[Measures].[Store Cost]>, resultStyle=VALUE)
Literal(name=Literal, class=class mondrian.calc.impl.ConstantCalc, type=MemberType<member=[Measures].[Store Cost]>,
resultStyle=VALUE_NOT_NULL, value=[Measures].[Store Cost])
2(name=2, class=class mondrian.olap.fun.SetFunDef$SetListCalc$2, type=MemberType<member=[Measures].[Unit Sales]>, resultStyle=VALUE)
Literal(name=Literal, class=class mondrian.calc.impl.ConstantCalc, type=MemberType<member=[Measures].[Unit Sales]>,
resultStyle=VALUE_NOT_NULL, value=[Measures].[Unit Sales])
Axis (ROWS):
Members(name=Members, class=class mondrian.olap.fun.LevelMembersFunDef$1, type=SetType<MemberType<level=[Customers].[State Province]>>,
resultStyle=MUTABLE_LIST)
Literal(name=Literal, class=class mondrian.calc.impl.ConstantCalc, type=LevelType<level=[Customers].[State Province]>,
resultStyle=VALUE_NOT_NULL, value=[Customers].[State Province])
result.profiling_plan
mondrian-olap query profiling
result.profiling_timing_string
SqlStatement-Segment.load invoked 1 times for total of 7ms. (Avg. 7ms/invocation)
SqlStatement-SqlTupleReader.readTuples [[Customers].[State Province]] invoked 1 times for total of
3ms. (Avg. 3ms/invocation)
result.total_duration
123
SQL logging in a string buffer
sql_logger = Java::org.apache.log4j.Logger.getLogger('mondrian.rolap.RolapUtil')
sql_logger.setAdditivity(false)
sql_log_buffer = StringIO.new
sql_log_stream = sql_log_buffer.to_outputstream
log_layout = org.apache.log4j.PatternLayout.new("%m%n")
log_appender = org.apache.log4j.WriterAppender.new(log_layout, @sql_log_stream)
class_synchronize { sql_logger.addAppender(log_appender) }
sql_logger.setLevel(org.apache.log4j.Level::DEBUG)
log_lines = sql_log_buffer.string.lines.map(&:strip)
# Always show the last log line as the last SQL probably didn't complete
last_log_line = log_lines.pop
# Filter SQL queries only for the current account using the table schema prefix
from_regexp = /^from #{Regexp.escape log_table_prefix}/
log_lines.grep(/done executing sql/).concat(Array(last_log_line)).map do |log_line|
formatted_sql_query = format_log_sql_query(log_line)
formatted_sql_query if formatted_sql_query =~ from_regexp
end.compact
SQL logging results
SqlTupleReader.readTuples [[Customers].[State Province]]: done executing sql [
select `d_customers`.`country` as `c0`, `d_customers`.`state_province` as `c1`
from `eazybi_development_dwh_20`.`d_customers` as `d_customers`
group by `d_customers`.`country`, `d_customers`.`state_province`
order by ISNULL(`d_customers`.`country`) ASC, `d_customers`.`country` ASC,
ISNULL(`d_customers`.`state_province`) ASC, `d_customers`.`state_province` ASC
], exec+fetch 3 ms, 3 rows, ex=8, close=8, open=[]
Segment.load: done executing sql [
select `d_customers`.`country` as `c0`, `d_customers`.`state_province` as `c1`,
sum(`sales`.`store_sales`) as `m0`, sum(`sales`.`store_cost`) as `m1`, sum(`sales`.`unit_sales`) as
`m2`
from `eazybi_development_dwh_20`.`d_customers` as `d_customers`, `eazybi_development_dwh_20`.`sales`
as `sales`
where `sales`.`customer_id` = `d_customers`.`id` and `d_customers`.`country` = 'USA'
group by `d_customers`.`country`, `d_customers`.`state_province`
], exec+fetch 7 ms, 3 rows, ex=9, close=9, open=[]
SqlStatement-Segment.load invoked 1 times for total of 7ms. (Avg. 7ms/invocation)
SqlStatement-SqlTupleReader.readTuples [[Customers].[State Province]] invoked 1 times for total of
3ms. (Avg. 3ms/invocation)
Demo
Production heap usage
Production heap usage
Mondrian connection and schema classes
Mondrian schema pool
/**
* A collection of schemas, identified by their connection properties
* (catalog name, JDBC URL, and so forth).
*/
class RolapSchemaPool {
private final Map<SchemaKey, ExpiringReference<RolapSchema>>
mapKeyToSchema =
new HashMap<SchemaKey, ExpiringReference<RolapSchema>>();
/**
* An expiring reference is a subclass of {@link SoftReference}
* which pins the reference in memory until a certain timeout
* is reached. After that, the reference is free to be garbage
* collected if needed.
*
* <p>The timeout value must be provided as a String representing
* both the time value and the time unit. For example, 1 second is
* represented as "1s". Valid time units are [d, h, m, s, ms],
* representing respectively days, hours, minutes, seconds and
* milliseconds.
*/
public class ExpiringReference<T> extends SoftReference<T> {
• Checkout / checkin Mondrian connections from a pool
• Store last used timestamp for a schema
• Periodically flush unused schemas
Flush unused Mondrian schemas
2018-11-23 07:43:18 +0000 INFO: flushed 11 schemas from total 122 schemas (0.080 sec)
2018-11-23 07:53:27 +0000 INFO: flushed 15 schemas from total 134 schemas (0.433 sec)
2018-11-23 08:03:38 +0000 INFO: flushed 20 schemas from total 137 schemas (0.138 sec)
2018-11-23 08:15:06 +0000 INFO: flushed 20 schemas from total 136 schemas (0.135 sec)
2018-11-23 08:25:27 +0000 INFO: flushed 21 schemas from total 134 schemas (0.196 sec)
2018-11-23 08:36:20 +0000 INFO: flushed 9 schemas from total 135 schemas (0.069 sec)
2018-11-23 08:47:00 +0000 INFO: flushed 11 schemas from total 144 schemas (0.176 sec)
2018-11-23 08:57:14 +0000 INFO: flushed 13 schemas from total 153 schemas (0.139 sec)
2018-11-23 09:08:31 +0000 INFO: flushed 22 schemas from total 160 schemas (0.163 sec)
2018-11-23 09:19:16 +0000 INFO: flushed 11 schemas from total 156 schemas (0.069 sec)
mondrian-olap flush schema
def self.raw_schema_pool
method = Java::mondrian.rolap.RolapSchemaPool.java_class.declared_method('instance')
method.accessible = true
method.invoke_static
end
def self.flush_schema_cache
method = Java::mondrian.rolap.RolapSchemaPool.java_class.declared_method('clear')
method.accessible = true
method.invoke(raw_schema_pool)
end
def self.flush_schema(schema_key)
method = Java::mondrian.rolap.RolapSchemaPool.java_class.declared_method('remove',
Java::mondrian.rolap.SchemaKey.java_class)
method.accessible = true
method.invoke(raw_schema_pool, raw_schema_key(schema_key))
end
Thank you!

github.com/rsim/mondrian-olap
raimonds.simanovskis@eazybi.com

More Related Content

Similar to Profiling Mondrian MDX Requests in a Production Environment

Mondrian - Geo Mondrian
Mondrian - Geo MondrianMondrian - Geo Mondrian
Mondrian - Geo MondrianSimone Campora
 
Effectively Deploying MongoDB on AEM
Effectively Deploying MongoDB on AEMEffectively Deploying MongoDB on AEM
Effectively Deploying MongoDB on AEMNorberto Leite
 
2012 09 MariaDB Boston Meetup - MariaDB 是 Mysql 的替代者吗
2012 09 MariaDB Boston Meetup - MariaDB 是 Mysql 的替代者吗2012 09 MariaDB Boston Meetup - MariaDB 是 Mysql 的替代者吗
2012 09 MariaDB Boston Meetup - MariaDB 是 Mysql 的替代者吗YUCHENG HU
 
What's New in MariaDB Server 10.2 and MariaDB MaxScale 2.1
What's New in MariaDB Server 10.2 and MariaDB MaxScale 2.1What's New in MariaDB Server 10.2 and MariaDB MaxScale 2.1
What's New in MariaDB Server 10.2 and MariaDB MaxScale 2.1MariaDB plc
 
What's New in MariaDB Server 10.2 and MariaDB MaxScale 2.1
What's New in MariaDB Server 10.2 and MariaDB MaxScale 2.1What's New in MariaDB Server 10.2 and MariaDB MaxScale 2.1
What's New in MariaDB Server 10.2 and MariaDB MaxScale 2.1MariaDB plc
 
sap basis transaction codes
sap basis transaction codessap basis transaction codes
sap basis transaction codesEOH SAP Services
 
Professional Services Insights into Improving Sitecore XP
Professional Services Insights into Improving Sitecore XPProfessional Services Insights into Improving Sitecore XP
Professional Services Insights into Improving Sitecore XPSeanHolmesby1
 
The State of the GeoServer project
The State of the GeoServer projectThe State of the GeoServer project
The State of the GeoServer projectGeoSolutions
 
Performance Optimization of Rails Applications
Performance Optimization of Rails ApplicationsPerformance Optimization of Rails Applications
Performance Optimization of Rails ApplicationsSerge Smetana
 
State of GeoServer at FOSS4G-NA
State of GeoServer at FOSS4G-NAState of GeoServer at FOSS4G-NA
State of GeoServer at FOSS4G-NAGeoSolutions
 
MySQL Performance Schema : fossasia
MySQL Performance Schema : fossasiaMySQL Performance Schema : fossasia
MySQL Performance Schema : fossasiaMayank Prasad
 
Vertical Slicing Architectures
Vertical Slicing ArchitecturesVertical Slicing Architectures
Vertical Slicing ArchitecturesVictor Rentea
 
WebPerformance: Why and How? – Stefan Wintermeyer
WebPerformance: Why and How? – Stefan WintermeyerWebPerformance: Why and How? – Stefan Wintermeyer
WebPerformance: Why and How? – Stefan WintermeyerElixir Club
 
Mysql Performance Schema - fossasia 2016
Mysql Performance Schema - fossasia 2016Mysql Performance Schema - fossasia 2016
Mysql Performance Schema - fossasia 2016Mayank Prasad
 
Understanding IBM Tivoli OMEGAMON for DB2 Batch Reporting, Customization and ...
Understanding IBM Tivoli OMEGAMON for DB2 Batch Reporting, Customization and ...Understanding IBM Tivoli OMEGAMON for DB2 Batch Reporting, Customization and ...
Understanding IBM Tivoli OMEGAMON for DB2 Batch Reporting, Customization and ...Cuneyt Goksu
 
Re-Design with Elixir/OTP
Re-Design with Elixir/OTPRe-Design with Elixir/OTP
Re-Design with Elixir/OTPMustafa TURAN
 
Welcome Webinar Slides
Welcome Webinar SlidesWelcome Webinar Slides
Welcome Webinar SlidesSumo Logic
 
Spark Summit EU talk by Nick Pentreath
Spark Summit EU talk by Nick PentreathSpark Summit EU talk by Nick Pentreath
Spark Summit EU talk by Nick PentreathSpark Summit
 
Ebs dba con4696_pdf_4696_0001
Ebs dba con4696_pdf_4696_0001Ebs dba con4696_pdf_4696_0001
Ebs dba con4696_pdf_4696_0001jucaab
 
Oracle Database Performance Tuning Advanced Features and Best Practices for DBAs
Oracle Database Performance Tuning Advanced Features and Best Practices for DBAsOracle Database Performance Tuning Advanced Features and Best Practices for DBAs
Oracle Database Performance Tuning Advanced Features and Best Practices for DBAsZohar Elkayam
 

Similar to Profiling Mondrian MDX Requests in a Production Environment (20)

Mondrian - Geo Mondrian
Mondrian - Geo MondrianMondrian - Geo Mondrian
Mondrian - Geo Mondrian
 
Effectively Deploying MongoDB on AEM
Effectively Deploying MongoDB on AEMEffectively Deploying MongoDB on AEM
Effectively Deploying MongoDB on AEM
 
2012 09 MariaDB Boston Meetup - MariaDB 是 Mysql 的替代者吗
2012 09 MariaDB Boston Meetup - MariaDB 是 Mysql 的替代者吗2012 09 MariaDB Boston Meetup - MariaDB 是 Mysql 的替代者吗
2012 09 MariaDB Boston Meetup - MariaDB 是 Mysql 的替代者吗
 
What's New in MariaDB Server 10.2 and MariaDB MaxScale 2.1
What's New in MariaDB Server 10.2 and MariaDB MaxScale 2.1What's New in MariaDB Server 10.2 and MariaDB MaxScale 2.1
What's New in MariaDB Server 10.2 and MariaDB MaxScale 2.1
 
What's New in MariaDB Server 10.2 and MariaDB MaxScale 2.1
What's New in MariaDB Server 10.2 and MariaDB MaxScale 2.1What's New in MariaDB Server 10.2 and MariaDB MaxScale 2.1
What's New in MariaDB Server 10.2 and MariaDB MaxScale 2.1
 
sap basis transaction codes
sap basis transaction codessap basis transaction codes
sap basis transaction codes
 
Professional Services Insights into Improving Sitecore XP
Professional Services Insights into Improving Sitecore XPProfessional Services Insights into Improving Sitecore XP
Professional Services Insights into Improving Sitecore XP
 
The State of the GeoServer project
The State of the GeoServer projectThe State of the GeoServer project
The State of the GeoServer project
 
Performance Optimization of Rails Applications
Performance Optimization of Rails ApplicationsPerformance Optimization of Rails Applications
Performance Optimization of Rails Applications
 
State of GeoServer at FOSS4G-NA
State of GeoServer at FOSS4G-NAState of GeoServer at FOSS4G-NA
State of GeoServer at FOSS4G-NA
 
MySQL Performance Schema : fossasia
MySQL Performance Schema : fossasiaMySQL Performance Schema : fossasia
MySQL Performance Schema : fossasia
 
Vertical Slicing Architectures
Vertical Slicing ArchitecturesVertical Slicing Architectures
Vertical Slicing Architectures
 
WebPerformance: Why and How? – Stefan Wintermeyer
WebPerformance: Why and How? – Stefan WintermeyerWebPerformance: Why and How? – Stefan Wintermeyer
WebPerformance: Why and How? – Stefan Wintermeyer
 
Mysql Performance Schema - fossasia 2016
Mysql Performance Schema - fossasia 2016Mysql Performance Schema - fossasia 2016
Mysql Performance Schema - fossasia 2016
 
Understanding IBM Tivoli OMEGAMON for DB2 Batch Reporting, Customization and ...
Understanding IBM Tivoli OMEGAMON for DB2 Batch Reporting, Customization and ...Understanding IBM Tivoli OMEGAMON for DB2 Batch Reporting, Customization and ...
Understanding IBM Tivoli OMEGAMON for DB2 Batch Reporting, Customization and ...
 
Re-Design with Elixir/OTP
Re-Design with Elixir/OTPRe-Design with Elixir/OTP
Re-Design with Elixir/OTP
 
Welcome Webinar Slides
Welcome Webinar SlidesWelcome Webinar Slides
Welcome Webinar Slides
 
Spark Summit EU talk by Nick Pentreath
Spark Summit EU talk by Nick PentreathSpark Summit EU talk by Nick Pentreath
Spark Summit EU talk by Nick Pentreath
 
Ebs dba con4696_pdf_4696_0001
Ebs dba con4696_pdf_4696_0001Ebs dba con4696_pdf_4696_0001
Ebs dba con4696_pdf_4696_0001
 
Oracle Database Performance Tuning Advanced Features and Best Practices for DBAs
Oracle Database Performance Tuning Advanced Features and Best Practices for DBAsOracle Database Performance Tuning Advanced Features and Best Practices for DBAs
Oracle Database Performance Tuning Advanced Features and Best Practices for DBAs
 

More from Raimonds Simanovskis

Improve Mondrian MDX usability with user defined functions
Improve Mondrian MDX usability with user defined functionsImprove Mondrian MDX usability with user defined functions
Improve Mondrian MDX usability with user defined functionsRaimonds Simanovskis
 
Analyze and Visualize Git Log for Fun and Profit - DevTernity 2015
Analyze and Visualize Git Log for Fun and Profit - DevTernity 2015Analyze and Visualize Git Log for Fun and Profit - DevTernity 2015
Analyze and Visualize Git Log for Fun and Profit - DevTernity 2015Raimonds Simanovskis
 
Data Warehouses and Multi-Dimensional Data Analysis
Data Warehouses and Multi-Dimensional Data AnalysisData Warehouses and Multi-Dimensional Data Analysis
Data Warehouses and Multi-Dimensional Data AnalysisRaimonds Simanovskis
 
eazyBI Overview - Embedding Mondrian in other applications
eazyBI Overview - Embedding Mondrian in other applicationseazyBI Overview - Embedding Mondrian in other applications
eazyBI Overview - Embedding Mondrian in other applicationsRaimonds Simanovskis
 
Atvērto datu izmantošanas pieredze Latvijā
Atvērto datu izmantošanas pieredze LatvijāAtvērto datu izmantošanas pieredze Latvijā
Atvērto datu izmantošanas pieredze LatvijāRaimonds Simanovskis
 
JavaScript Unit Testing with Jasmine
JavaScript Unit Testing with JasmineJavaScript Unit Testing with Jasmine
JavaScript Unit Testing with JasmineRaimonds Simanovskis
 
JRuby - Programmer's Best Friend on JVM
JRuby - Programmer's Best Friend on JVMJRuby - Programmer's Best Friend on JVM
JRuby - Programmer's Best Friend on JVMRaimonds Simanovskis
 
Agile Operations or How to sleep better at night
Agile Operations or How to sleep better at nightAgile Operations or How to sleep better at night
Agile Operations or How to sleep better at nightRaimonds Simanovskis
 
Analyze and Visualize Git Log for Fun and Profit
Analyze and Visualize Git Log for Fun and ProfitAnalyze and Visualize Git Log for Fun and Profit
Analyze and Visualize Git Log for Fun and ProfitRaimonds Simanovskis
 
opendata.lv Case Study - Promote Open Data with Analytics and Visualizations
opendata.lv Case Study - Promote Open Data with Analytics and Visualizationsopendata.lv Case Study - Promote Open Data with Analytics and Visualizations
opendata.lv Case Study - Promote Open Data with Analytics and VisualizationsRaimonds Simanovskis
 
Extending Oracle E-Business Suite with Ruby on Rails
Extending Oracle E-Business Suite with Ruby on RailsExtending Oracle E-Business Suite with Ruby on Rails
Extending Oracle E-Business Suite with Ruby on RailsRaimonds Simanovskis
 
Rails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
Rails-like JavaScript Using CoffeeScript, Backbone.js and JasmineRails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
Rails-like JavaScript Using CoffeeScript, Backbone.js and JasmineRaimonds Simanovskis
 
RailsWayCon: Multidimensional Data Analysis with JRuby
RailsWayCon: Multidimensional Data Analysis with JRubyRailsWayCon: Multidimensional Data Analysis with JRuby
RailsWayCon: Multidimensional Data Analysis with JRubyRaimonds Simanovskis
 
Why Every Tester Should Learn Ruby
Why Every Tester Should Learn RubyWhy Every Tester Should Learn Ruby
Why Every Tester Should Learn RubyRaimonds Simanovskis
 
Multidimensional Data Analysis with JRuby
Multidimensional Data Analysis with JRubyMultidimensional Data Analysis with JRuby
Multidimensional Data Analysis with JRubyRaimonds Simanovskis
 
Rails-like JavaScript using CoffeeScript, Backbone.js and Jasmine
Rails-like JavaScript using CoffeeScript, Backbone.js and JasmineRails-like JavaScript using CoffeeScript, Backbone.js and Jasmine
Rails-like JavaScript using CoffeeScript, Backbone.js and JasmineRaimonds Simanovskis
 

More from Raimonds Simanovskis (20)

Improve Mondrian MDX usability with user defined functions
Improve Mondrian MDX usability with user defined functionsImprove Mondrian MDX usability with user defined functions
Improve Mondrian MDX usability with user defined functions
 
Analyze and Visualize Git Log for Fun and Profit - DevTernity 2015
Analyze and Visualize Git Log for Fun and Profit - DevTernity 2015Analyze and Visualize Git Log for Fun and Profit - DevTernity 2015
Analyze and Visualize Git Log for Fun and Profit - DevTernity 2015
 
Data Warehouses and Multi-Dimensional Data Analysis
Data Warehouses and Multi-Dimensional Data AnalysisData Warehouses and Multi-Dimensional Data Analysis
Data Warehouses and Multi-Dimensional Data Analysis
 
mondrian-olap JRuby library
mondrian-olap JRuby librarymondrian-olap JRuby library
mondrian-olap JRuby library
 
eazyBI Overview - Embedding Mondrian in other applications
eazyBI Overview - Embedding Mondrian in other applicationseazyBI Overview - Embedding Mondrian in other applications
eazyBI Overview - Embedding Mondrian in other applications
 
Atvērto datu izmantošanas pieredze Latvijā
Atvērto datu izmantošanas pieredze LatvijāAtvērto datu izmantošanas pieredze Latvijā
Atvērto datu izmantošanas pieredze Latvijā
 
JavaScript Unit Testing with Jasmine
JavaScript Unit Testing with JasmineJavaScript Unit Testing with Jasmine
JavaScript Unit Testing with Jasmine
 
JRuby - Programmer's Best Friend on JVM
JRuby - Programmer's Best Friend on JVMJRuby - Programmer's Best Friend on JVM
JRuby - Programmer's Best Friend on JVM
 
Agile Operations or How to sleep better at night
Agile Operations or How to sleep better at nightAgile Operations or How to sleep better at night
Agile Operations or How to sleep better at night
 
TDD - Why and How?
TDD - Why and How?TDD - Why and How?
TDD - Why and How?
 
Analyze and Visualize Git Log for Fun and Profit
Analyze and Visualize Git Log for Fun and ProfitAnalyze and Visualize Git Log for Fun and Profit
Analyze and Visualize Git Log for Fun and Profit
 
PL/SQL Unit Testing Can Be Fun
PL/SQL Unit Testing Can Be FunPL/SQL Unit Testing Can Be Fun
PL/SQL Unit Testing Can Be Fun
 
opendata.lv Case Study - Promote Open Data with Analytics and Visualizations
opendata.lv Case Study - Promote Open Data with Analytics and Visualizationsopendata.lv Case Study - Promote Open Data with Analytics and Visualizations
opendata.lv Case Study - Promote Open Data with Analytics and Visualizations
 
Extending Oracle E-Business Suite with Ruby on Rails
Extending Oracle E-Business Suite with Ruby on RailsExtending Oracle E-Business Suite with Ruby on Rails
Extending Oracle E-Business Suite with Ruby on Rails
 
Rails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
Rails-like JavaScript Using CoffeeScript, Backbone.js and JasmineRails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
Rails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
 
RailsWayCon: Multidimensional Data Analysis with JRuby
RailsWayCon: Multidimensional Data Analysis with JRubyRailsWayCon: Multidimensional Data Analysis with JRuby
RailsWayCon: Multidimensional Data Analysis with JRuby
 
Why Every Tester Should Learn Ruby
Why Every Tester Should Learn RubyWhy Every Tester Should Learn Ruby
Why Every Tester Should Learn Ruby
 
Multidimensional Data Analysis with JRuby
Multidimensional Data Analysis with JRubyMultidimensional Data Analysis with JRuby
Multidimensional Data Analysis with JRuby
 
Rails on Oracle 2011
Rails on Oracle 2011Rails on Oracle 2011
Rails on Oracle 2011
 
Rails-like JavaScript using CoffeeScript, Backbone.js and Jasmine
Rails-like JavaScript using CoffeeScript, Backbone.js and JasmineRails-like JavaScript using CoffeeScript, Backbone.js and Jasmine
Rails-like JavaScript using CoffeeScript, Backbone.js and Jasmine
 

Recently uploaded

5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdfWave PLM
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...gurkirankumar98700
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)OPEN KNOWLEDGE GmbH
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityNeo4j
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - InfographicHr365.us smith
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideChristina Lin
 
Engage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyEngage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyFrank van der Linden
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...ICS
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about usDynamic Netsoft
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...soniya singh
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providermohitmore19
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...MyIntelliSource, Inc.
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptkotipi9215
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 
Introduction to Decentralized Applications (dApps)
Introduction to Decentralized Applications (dApps)Introduction to Decentralized Applications (dApps)
Introduction to Decentralized Applications (dApps)Intelisync
 

Recently uploaded (20)

Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered Sustainability
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - Infographic
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
 
Engage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyEngage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The Ugly
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
Exploring iOS App Development: Simplifying the Process
Exploring iOS App Development: Simplifying the ProcessExploring iOS App Development: Simplifying the Process
Exploring iOS App Development: Simplifying the Process
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about us
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.ppt
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
Introduction to Decentralized Applications (dApps)
Introduction to Decentralized Applications (dApps)Introduction to Decentralized Applications (dApps)
Introduction to Decentralized Applications (dApps)
 

Profiling Mondrian MDX Requests in a Production Environment

  • 1. Profiling Mondrian MDX Requests in a Production Environment Raimonds Simanovskis @rsim
  • 2. Make All Mondrian MDX Requests Super Fast in a Production Environment What Takes So Long Time When Mondrian MDX Requests Are Slow?
  • 5. Single JVM process Big Monolithic Application Multi-tenant web application mondrian-olap JRuby library Mondrian Schema and segment cache DB schema 1 Dimension4Dimension3 Dimension2Dimension1 Measure DB schema 2 Dimension4Dimension3 Dimension2Dimension1 Measure DB schema 10 000 Dimension4Dimension3 Dimension2Dimension1 Measure DB schema 10 001 Dimension4Dimension3 Dimension2Dimension1 Measure … …
  • 9. Black Mondrian Magic Mondrian Schema and segment cache DB schema Dimension4Dimension3 Dimension2Dimension1 Measure SELECT {[Measures].[Store Sales], [Measures].[Store Cost], [Measures].[Unit Sales] } ON COLUMNS, [Customers].[State Province].Members ON ROWS FROM [Sales] select `d_customers`.`country` as `c0`, `d_customers`.`state_province` as `c1` from `eazybi_development_dwh_20`.`d_customers` as `d_customers` group by `d_customers`.`country`, `d_customers`.`state_province` order by ISNULL(`d_customers`.`country`) ASC, `d_customers`.`country` ASC, ISNULL(`d_customers`.`state_province`) ASC, `d_customers`.`state_province` ASC select `d_customers`.`country` as `c0`, `d_customers`.`state_province` as `c1`, sum(`sales`.`store_sales`) as `m0`, sum(`sales`.`store_cost`) as `m1`, sum(`sales`.`unit_sales`) as `m2` from `eazybi_development_dwh_20`.`d_customers` as `d_customers`, `eazybi_development_dwh_20`.`sales` as `sales` where `sales`.`customer_id` = `d_customers`.`id` and `d_customers`.`country` = 'USA' group by `d_customers`.`country`, `d_customers`.`state_province`
  • 10. Debugging in development log4j.rootLogger=DEBUG, MONDRIAN log4j.appender.MONDRIAN=org.apache.log4j.ConsoleAppender log4j.appender.MONDRIAN.layout=org.apache.log4j.PatternLayout log4j.appender.MONDRIAN.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss Z} %-5p [%c] %m%n log4j.category.mondrian.mdx=DEBUG, MONDRIAN log4j.category.mondrian.sql=DEBUG, MONDRIAN
  • 11. Debugging in development 2018-11-22 16:32:02 +0000 DEBUG [mondrian.mdx] 308: select {[Measures].[Store Sales], [Measures]. [Store Cost], [Measures].[Unit Sales]} ON COLUMNS, [Customers].[State Province].Members ON ROWS from [Sales] 2018-11-22 16:32:02 +0000 DEBUG [mondrian.sql] 7: SqlTupleReader.readTuples [[Customers].[State Province]]: executing sql [select `d_customers`.`country` as `c0`, `d_customers`.`state_province` as `c1` from `eazybi_development_dwh_20`.`d_customers` as `d_customers` group by `d_customers`.`country`, `d_customers`.`state_province` order by ISNULL(`d_customers`.`country`) ASC, `d_customers`.`country` ASC, ISNULL(`d_customers`.`state_province`) ASC, `d_customers`.`state_province` ASC] 2018-11-22 16:32:02 +0000 DEBUG [mondrian.sql] 7: , exec 0 ms 2018-11-22 16:32:02 +0000 DEBUG [mondrian.sql] 7: , exec+fetch 3 ms, 3 rows 2018-11-22 16:32:02 +0000 DEBUG [mondrian.sql] 8: Segment.load: executing sql [select `d_customers`.`country` as `c0`, `d_customers`.`state_province` as `c1`, sum(`sales`.`store_sales`) as `m0`, sum(`sales`.`store_cost`) as `m1`, sum(`sales`.`unit_sales`) as `m2` from `eazybi_development_dwh_20`.`d_customers` as `d_customers`, `eazybi_development_dwh_20`.`sales` as `sales` where `sales`.`customer_id` = `d_customers`.`id` and `d_customers`.`country` = 'USA' group by `d_customers`.`country`, `d_customers`.`state_province`] 2018-11-22 16:32:02 +0000 DEBUG [mondrian.sql] 8: , exec 0 ms 2018-11-22 16:32:02 +0000 DEBUG [mondrian.sql] 8: , exec+fetch 7 ms, 3 rows 2018-11-22 16:32:02 +0000 DEBUG [mondrian.mdx] 308: exec: 68 ms
  • 12. Query Timing and Profiling /** * Provides hooks for recording timing information of components of Query * execution. * * <p>NOTE: This class is experimental and subject to change/removal * without notice. * * <p>Code that executes as part of a Query can call * {@link QueryTiming#markStart(String)} * before executing, and {@link QueryTiming#markEnd(String)} afterwards, or can * track execution times manually and call * {@link QueryTiming#markFull(String, long)}. * * <p>To read timing information, add a handler to the statement using * {@link mondrian.server.Statement#enableProfiling} and implement the * {@link mondrian.spi.ProfileHandler#explain(String, QueryTiming)} method. * * @author jbarnett */ public class QueryTiming {
  • 13. Query Timing and Profiling /** * Provides hooks for recording timing information of components of Query * execution. * * <p>NOTE: This class is experimental and subject to change/removal * without notice. * * <p>Code that executes as part of a Query can call * {@link QueryTiming#markStart(String)} * before executing, and {@link QueryTiming#markEnd(String)} afterwards, or can * track execution times manually and call * {@link QueryTiming#markFull(String, long)}. * * <p>To read timing information, add a handler to the statement using * {@link mondrian.server.Statement#enableProfiling} and implement the * {@link mondrian.spi.ProfileHandler#explain(String, QueryTiming)} method. * * @author jbarnett */ public class QueryTiming {
  • 14. mondrian-olap query profiling result = connection.execute( "SELECT {[Measures].[Store Sales], [Measures].[Store Cost], [Measures].[Unit Sales]} ON COLUMNS " "[Customers].[State Province].Members ON ROWS " "FROM [Sales]", profiling: true ) Axis (COLUMNS): SetListCalc(name=SetListCalc, class=class mondrian.olap.fun.SetFunDef$SetListCalc, type=SetType<MemberType<member=[Measures].[Store Sales]>>, resultStyle=MUTABLE_LIST) 2(name=2, class=class mondrian.olap.fun.SetFunDef$SetListCalc$2, type=MemberType<member=[Measures].[Store Sales]>, resultStyle=VALUE) Literal(name=Literal, class=class mondrian.calc.impl.ConstantCalc, type=MemberType<member=[Measures].[Store Sales]>, resultStyle=VALUE_NOT_NULL, value=[Measures].[Store Sales]) 2(name=2, class=class mondrian.olap.fun.SetFunDef$SetListCalc$2, type=MemberType<member=[Measures].[Store Cost]>, resultStyle=VALUE) Literal(name=Literal, class=class mondrian.calc.impl.ConstantCalc, type=MemberType<member=[Measures].[Store Cost]>, resultStyle=VALUE_NOT_NULL, value=[Measures].[Store Cost]) 2(name=2, class=class mondrian.olap.fun.SetFunDef$SetListCalc$2, type=MemberType<member=[Measures].[Unit Sales]>, resultStyle=VALUE) Literal(name=Literal, class=class mondrian.calc.impl.ConstantCalc, type=MemberType<member=[Measures].[Unit Sales]>, resultStyle=VALUE_NOT_NULL, value=[Measures].[Unit Sales]) Axis (ROWS): Members(name=Members, class=class mondrian.olap.fun.LevelMembersFunDef$1, type=SetType<MemberType<level=[Customers].[State Province]>>, resultStyle=MUTABLE_LIST) Literal(name=Literal, class=class mondrian.calc.impl.ConstantCalc, type=LevelType<level=[Customers].[State Province]>, resultStyle=VALUE_NOT_NULL, value=[Customers].[State Province]) result.profiling_plan
  • 15. mondrian-olap query profiling result.profiling_timing_string SqlStatement-Segment.load invoked 1 times for total of 7ms. (Avg. 7ms/invocation) SqlStatement-SqlTupleReader.readTuples [[Customers].[State Province]] invoked 1 times for total of 3ms. (Avg. 3ms/invocation) result.total_duration 123
  • 16. SQL logging in a string buffer sql_logger = Java::org.apache.log4j.Logger.getLogger('mondrian.rolap.RolapUtil') sql_logger.setAdditivity(false) sql_log_buffer = StringIO.new sql_log_stream = sql_log_buffer.to_outputstream log_layout = org.apache.log4j.PatternLayout.new("%m%n") log_appender = org.apache.log4j.WriterAppender.new(log_layout, @sql_log_stream) class_synchronize { sql_logger.addAppender(log_appender) } sql_logger.setLevel(org.apache.log4j.Level::DEBUG) log_lines = sql_log_buffer.string.lines.map(&:strip) # Always show the last log line as the last SQL probably didn't complete last_log_line = log_lines.pop # Filter SQL queries only for the current account using the table schema prefix from_regexp = /^from #{Regexp.escape log_table_prefix}/ log_lines.grep(/done executing sql/).concat(Array(last_log_line)).map do |log_line| formatted_sql_query = format_log_sql_query(log_line) formatted_sql_query if formatted_sql_query =~ from_regexp end.compact
  • 17. SQL logging results SqlTupleReader.readTuples [[Customers].[State Province]]: done executing sql [ select `d_customers`.`country` as `c0`, `d_customers`.`state_province` as `c1` from `eazybi_development_dwh_20`.`d_customers` as `d_customers` group by `d_customers`.`country`, `d_customers`.`state_province` order by ISNULL(`d_customers`.`country`) ASC, `d_customers`.`country` ASC, ISNULL(`d_customers`.`state_province`) ASC, `d_customers`.`state_province` ASC ], exec+fetch 3 ms, 3 rows, ex=8, close=8, open=[] Segment.load: done executing sql [ select `d_customers`.`country` as `c0`, `d_customers`.`state_province` as `c1`, sum(`sales`.`store_sales`) as `m0`, sum(`sales`.`store_cost`) as `m1`, sum(`sales`.`unit_sales`) as `m2` from `eazybi_development_dwh_20`.`d_customers` as `d_customers`, `eazybi_development_dwh_20`.`sales` as `sales` where `sales`.`customer_id` = `d_customers`.`id` and `d_customers`.`country` = 'USA' group by `d_customers`.`country`, `d_customers`.`state_province` ], exec+fetch 7 ms, 3 rows, ex=9, close=9, open=[] SqlStatement-Segment.load invoked 1 times for total of 7ms. (Avg. 7ms/invocation) SqlStatement-SqlTupleReader.readTuples [[Customers].[State Province]] invoked 1 times for total of 3ms. (Avg. 3ms/invocation)
  • 18. Demo
  • 21. Mondrian connection and schema classes
  • 22. Mondrian schema pool /** * A collection of schemas, identified by their connection properties * (catalog name, JDBC URL, and so forth). */ class RolapSchemaPool { private final Map<SchemaKey, ExpiringReference<RolapSchema>> mapKeyToSchema = new HashMap<SchemaKey, ExpiringReference<RolapSchema>>(); /** * An expiring reference is a subclass of {@link SoftReference} * which pins the reference in memory until a certain timeout * is reached. After that, the reference is free to be garbage * collected if needed. * * <p>The timeout value must be provided as a String representing * both the time value and the time unit. For example, 1 second is * represented as "1s". Valid time units are [d, h, m, s, ms], * representing respectively days, hours, minutes, seconds and * milliseconds. */ public class ExpiringReference<T> extends SoftReference<T> {
  • 23. • Checkout / checkin Mondrian connections from a pool • Store last used timestamp for a schema • Periodically flush unused schemas Flush unused Mondrian schemas 2018-11-23 07:43:18 +0000 INFO: flushed 11 schemas from total 122 schemas (0.080 sec) 2018-11-23 07:53:27 +0000 INFO: flushed 15 schemas from total 134 schemas (0.433 sec) 2018-11-23 08:03:38 +0000 INFO: flushed 20 schemas from total 137 schemas (0.138 sec) 2018-11-23 08:15:06 +0000 INFO: flushed 20 schemas from total 136 schemas (0.135 sec) 2018-11-23 08:25:27 +0000 INFO: flushed 21 schemas from total 134 schemas (0.196 sec) 2018-11-23 08:36:20 +0000 INFO: flushed 9 schemas from total 135 schemas (0.069 sec) 2018-11-23 08:47:00 +0000 INFO: flushed 11 schemas from total 144 schemas (0.176 sec) 2018-11-23 08:57:14 +0000 INFO: flushed 13 schemas from total 153 schemas (0.139 sec) 2018-11-23 09:08:31 +0000 INFO: flushed 22 schemas from total 160 schemas (0.163 sec) 2018-11-23 09:19:16 +0000 INFO: flushed 11 schemas from total 156 schemas (0.069 sec)
  • 24. mondrian-olap flush schema def self.raw_schema_pool method = Java::mondrian.rolap.RolapSchemaPool.java_class.declared_method('instance') method.accessible = true method.invoke_static end def self.flush_schema_cache method = Java::mondrian.rolap.RolapSchemaPool.java_class.declared_method('clear') method.accessible = true method.invoke(raw_schema_pool) end def self.flush_schema(schema_key) method = Java::mondrian.rolap.RolapSchemaPool.java_class.declared_method('remove', Java::mondrian.rolap.SchemaKey.java_class) method.accessible = true method.invoke(raw_schema_pool, raw_schema_key(schema_key)) end