{"id":444,"date":"2009-11-02T23:49:27","date_gmt":"2009-11-03T06:49:27","guid":{"rendered":"http:\/\/www.nicholasgoodman.com\/bt\/blog\/?p=444"},"modified":"2009-11-02T23:49:27","modified_gmt":"2009-11-03T06:49:27","slug":"instant-relief-from-slow-mysql-reporting-queries-using-dynamodb","status":"publish","type":"post","link":"http:\/\/www.nicholasgoodman.com\/bt\/blog\/2009\/11\/02\/instant-relief-from-slow-mysql-reporting-queries-using-dynamodb\/","title":{"rendered":"Instant Relief from Slow MySQL Reporting Queries using DynamoDB"},"content":{"rendered":"<p>Here&#8217;s the scenario.  You&#8217;ve got a table in MySQL for reporting that has a few million rows, and is denormalized for reporting.  You&#8217;ve got a Pentaho Report that is querying this MySQL table.  You have two problems with the current report.<\/p>\n<ol>\n<li>Your users are complaining that the query is <strong>slow<\/strong>, and they have to wait around for longer than they&#8217;d like to see their report. (approx 40s)<\/li>\n<li>Your DBAs are cranky because they see the <strong>size<\/strong> of this table is getting bigger.  (approx 1.8GB)<\/li>\n<\/ol>\n<p>MySQL is fundamentally designed to be an OLTP database and while it does a fantastic job at that, its data warehouse features were built as &#8220;bolt on&#8221; additions.  Can it be used for BI? Absolutely, I&#8217;ve used it a many customer sites.  Does DynamoDB provide a better set of features\/capabilities for doing BI?  We think so!  Are they both 100% open source?  You bet;why not choose the right tool for the right job then?<\/p>\n<p>DynamoDB (aka LucidDB) is a &#8220;<em>purpose built for BI&#8221;<\/em> database.  What does that mean?  Well, I&#8217;ll be blogging about a lot of features that speak to our philosophy of a complete &#8220;BI Database&#8221; not just a fast one.  One of the features that makes LucidDB complete, and not just a drag racer, is its ability to connect to remote data sources via JDBC and retrieve data.  If you&#8217;re doing simple table replications, you don&#8217;t have to use an ETL tool, or do export or imports, or LOAD DATA INFILEs, etc.  Our ability to connect to remote databases and access them as &#8220;remote tables&#8221; makes retrieving data into DynamoDB as easy as &#8220;insert into mytable select * from remote_table.&#8221;<\/p>\n<p>Back to our original issue with our current MySQL<\/p>\n<p>Our report is <strong>slow<\/strong>, and our database is <strong>big<\/strong>.  How slow?  Well, not really that bad, but at about 40s per query run that&#8217;s enough to tempt your business analyst to go fetch a coffee instead of continuing his work.  How big?  Well, not really that big, but at about 1.8GB it&#8217;s starting to get non trivial in terms of tuning the I\/O etc.<\/p>\n<p><strong>Our goal is to improve both using DynamoDB<\/strong>; we&#8217;ll leave MySQL as our main OLTP application.  We&#8217;re not trying to replace it &#8211; in fact, we&#8217;ll embrace MySQL as the system of record and simply &#8220;slurp\/report&#8221; off this table in a separate reporting environment.<\/p>\n<p>It&#8217;s a two step process.<\/p>\n<ol>\n<li>Connect from DynamoDB to MySQL using a JDBC connector, access the remote table, and draw over the data using a simple INSERT statement.<\/li>\n<li>Change our Pentaho Report to use the DynamoDB JDBC connector instead of MySQL.<\/li>\n<\/ol>\n<p><img decoding=\"async\" src=\"\/entry_images\/2009-11-02_2301.png\" hspace=\"4\" vspace=\"4\" \/><\/p>\n<p>Our Pentaho Report is based on the following SQL<\/p>\n<blockquote><p>SELECT t.Carrier as &#8220;CARRIER&#8221;,<br \/>\nc as &#8220;C&#8221;, c2 as &#8220;C2&#8221;, c*1000\/c2 as &#8220;C3&#8221; FROM<br \/>\n(SELECT Carrier, count(Carrier) AS c FROM ontime<br \/>\nWHERE DepDelay&gt;10 GROUP BY Carrier) t JOIN<br \/>\n(SELECT Carrier, count(Carrier) AS c2 FROM ontime<br \/>\nGROUP BY Carrier) t2 ON (t.Carrier=t2.Carrier) ORDER BY c3 DESC;<\/p><\/blockquote>\n<p><a href=\"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-content\/uploads\/2009\/11\/200911022216.jpg\" onclick=\"window.open('http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-content\/uploads\/2009\/11\/200911022216.jpg','popup','width=625,height=534,scrollbars=no,resizable=yes,toolbar=no,directories=no,location=no,menubar=no,status=yes,left=0,top=0');return false\"><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-content\/uploads\/2009\/11\/200911022216-tm.jpg\" height=\"100\" width=\"117\" border=\"1\" hspace=\"4\" vspace=\"4\" alt=\"200911022216\" \/><\/a><br \/>\nThis takes approximately 40s to run on MySQL database running the same machine.<\/p>\n<p><strong>Step 1:  Connect, and load the data into our DynamoDB table.<\/strong><\/p>\n<blockquote><p>&#8212; Create DynamoDB reporting table first<br \/>\ncreate schema faster;<\/p>\n<p>create table faster.&#8221;ontime&#8221; (<br \/>\n&#8220;Year&#8221; int,<br \/>\n&#8220;Quarter&#8221; tinyint ,<br \/>\n&#8220;Month&#8221; tinyint ,<br \/>\n&#8230;.. Abbreviated for Brevity &#8230;.<br \/>\n&#8220;Div5TailNum&#8221; varchar(10)<br \/>\n);<\/p>\n<p>&#8212; Get access the MySQL table OnTime in the OTP schema on host localhost<br \/>\ncreate schema MYSQL_SOURCE;<br \/>\nset schema &#8216;MYSQL_SOURCE&#8217;;<\/p>\n<p>CREATE SERVER MYSQL_REMOTE_SOURCE FOREIGN DATA WRAPPER<br \/>\nsys_jdbc OPTIONS (<br \/>\ndriver_class &#8216;com.mysql.jdbc.Driver&#8217;,<br \/>\nurl &#8216;jdbc:mysql:\/\/localhost\/otp?useCursorFetch=true&#8217;,<br \/>\nuser_name &#8216;root&#8217;,<br \/>\npassword &#8216;easy&#8217;,<br \/>\nfetch_size &#8216;1000&#8217;,<br \/>\ntable_types &#8216;TABLE&#8217;,<br \/>\nschema_name &#8216;otp&#8217;);<\/p>\n<p>import foreign schema OTP from server MYSQL_REMOTE_SOURCE into MYSQL_SOURCE;<\/p>\n<p>&#8212; Load DynamoDB table from MySQL database directly<br \/>\ninsert into FASTER.&#8221;ontime&#8221; select * from MYSQL_SOURCE.&#8221;ontime&#8221;;<\/p>\n<p>Notice that last statement.  You don&#8217;t have to export to intermediate files, or use an ETL tool (not that that&#8217;s bad, I&#8217;m a big fan of ETL tools!).  You can use good old fashioned SQL to get data from a remote database into DynamoDB.<\/p><\/blockquote>\n<p><strong>Step 2: Change the Pentaho Report to use the new connection.<\/strong><\/p>\n<blockquote><p>We open up our report and change our connection from MySQL<\/p>\n<p><a href=\"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-content\/uploads\/2009\/11\/200911022234.jpg\" onclick=\"window.open('http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-content\/uploads\/2009\/11\/200911022234.jpg','popup','width=403,height=446,scrollbars=no,resizable=yes,toolbar=no,directories=no,location=no,menubar=no,status=yes,left=0,top=0');return false\"><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-content\/uploads\/2009\/11\/200911022234-tm.jpg\" height=\"100\" width=\"90\" border=\"1\" hspace=\"4\" vspace=\"4\" alt=\"200911022234\" \/><\/a><br \/>\nto DynamoDB<\/p>\n<p><a href=\"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-content\/uploads\/2009\/11\/200911022236.jpg\" onclick=\"window.open('http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-content\/uploads\/2009\/11\/200911022236.jpg','popup','width=589,height=454,scrollbars=no,resizable=yes,toolbar=no,directories=no,location=no,menubar=no,status=yes,left=0,top=0');return false\"><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-content\/uploads\/2009\/11\/200911022236-tm.jpg\" height=\"100\" width=\"129\" border=\"1\" hspace=\"4\" vspace=\"4\" alt=\"200911022236\" \/><\/a><br \/>\nNOTE: Until we finish our QA&#8217;ed builds we&#8217;re using LucidDB driver instead of DynamoDB but they are, one and the same.<\/p><\/blockquote>\n<p>We make some minor adjustment to the SQL (quoting some tables\/etc) and rerun our query and Voila, <strong>our report runs in 10s down from 40s, an improvement of 400%.<br \/>\n<\/strong><br \/>\nHow about storage?  <strong>Our storage report shows that DynamoDB is using only .3 GB to store the same 7 Million records as compared to MySQL at 1.8GB, or 1\/6 of the storage.<\/p>\n<p><\/strong>Not a bad investment of a few minutes of time, I&#8217;d say.  DynamoDB (<a href=\"http:\/\/www.luciddb.org\">LucidDB<\/a>) takes just a few minutes to install, and because of its focus on BI you should find things like retrieving data from remote data sources easy, and effective.  Let&#8217;s be truthful here as well; once you speed up a report by 400% and reduce its storage by 6x your boss will be calling <strong><em>you<\/em><\/strong> a dynamo.<\/p>\n<p>Notes:  Full set of scripts posted here: <a href=\"\/entry_images\/mysql_relief.zip\">mysql_relief.zip<\/a>.  Original queries and dataset from Vadim at <a href=\"http:\/\/www.mysqlperformanceblog.com\">MySQLPerformanceBlog<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Here&#8217;s the scenario. You&#8217;ve got a table in MySQL for reporting that has a few million rows, and is denormalized for reporting. You&#8217;ve got a Pentaho Report that is querying this MySQL table. You have two problems with the current report. Your users are complaining that the query is slow, and they have to wait [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[5,11],"tags":[],"_links":{"self":[{"href":"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-json\/wp\/v2\/posts\/444"}],"collection":[{"href":"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-json\/wp\/v2\/comments?post=444"}],"version-history":[{"count":0,"href":"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-json\/wp\/v2\/posts\/444\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-json\/wp\/v2\/media?parent=444"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-json\/wp\/v2\/categories?post=444"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-json\/wp\/v2\/tags?post=444"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}