Search This Blog

Wednesday, January 30, 2008

Tips for Writing High-performance SQL

Tips for Writing High-performance SQL
These tips apply broadly when writing high-performance stored procedures. Unfortunately, unlike some tips, you can't simply apply most of them without first considering the nature and schema of the data you're querying.

  1. Avoid using cursors (as well as other looping structures) as much as possible. Cursors are inefficient, and database engines usually don't have the best loop implementations in terms of performance.

    On the database side, you can usually replace code involving cursors with aggregate SQL statements (SELECT, INSERT, and UPDATE) that use vector tables. All database engines are heavily optimized for aggregate statements, so even if a loop is unavoidable, it is always better to execute a few aggregate statements in a loop with a small number of iterations, than to create a cursor and execute simple statements over a large number of iterations.

    Even if initial performance tests, especially with a small amount of data, show cursors to be more efficient than a complex aggregate statement, it is worthwhile to try to optimize the operation by breaking it into smaller portions or using other approaches—unless you can guarantee that the data value will stay small. Cursor approaches will not scale.

  2. Filter data wisely. One alternative to using cursors uses a fall-through approach, filtering and aggregating data in multiple steps via a set of data storages, which could be physical tables, temporary tables, or table variables. It is usually best to include some aggregate filters into aggregate statements to filter out the majority of data in one simple shot whenever necessary, working on smaller amounts of data. Then you can proceed with joining and filtering, making sure to keep the number of join permutations under control at all times.

  3. It is usually more efficient to execute multiple statements with one condition than a single statement with multiple OR conditions when executing UPDATE and DELETE statements against permanent database tables that can be accessed by multiple users simultaneously. This tip is especially important from the scalability point of view; from the performance point of view the difference is usually marginal. The major reason for the tip is the locking of the database records and the lock escalations that occur behind the scenes.

  4. Make wise distinctions between temp tables and table variables. Table variables are in-memory structures that may work from 2-100 times faster than temp tables. But keep in mind that access to table variables gets slower as the volume of data they contain grows. At some point, table variables will overflow the available memory and that kills the performance. Therefore, use table variables only when their data content is guaranteed not to grow unpredictably; the breaking size is around several thousand records. For larger data volumes, I recommend temp tables with clustered indexes. Interestingly, I've found that a temp table with one clustered index is often faster than having multiple simple indexes. In contrast, multiple simple indexes with physical tables are often faster than one clustered index.

  5. Make careful distinctions between hard rules and assumptions. This is more of a business design tip, which applies more to code design than to performance and scalability design in general. In real life however, performance and scalability are generally the first things to suffer from improper design. When rules are implemented as assumptions, they usually cause unnecessary calculations to be performed, affecting performance. However, when assumptions are implemented as rules they tend to cause errors and algorithm failures, which usually requires an urgent redesign. That, in turn, is usually performed with business constraints and results in inefficient final algorithms. That's because bad design decisions are often corrected in a rush and without sufficient resources—sometimes under pressure from customers whose businesses are usually in a critical stage when problems are uncovered, but must continue operating during the process.

  6. Pay attention to join order. Using proper join order sometimes lets the database engine generate hints that execute joins with an optimal amount of records. Most database engines also support hard hints, but in most cases you should avoid using hard hints and let the database engine figure out the best way to do its job on its own.

  7. Be careful when joining complex views to other views and database tables in complex SELECT statements. When the database contains a significant amount of data, SQL Server engine tends to recalculate the execution plan of the resulting statement, which often results in an inefficient execution plan and may kill the performance. The most difficult part is that the behavior of SQL Server engine is inconsistent in that respect, and heavily depends on the database size, indexes, foreign keys, and other database structures and constraints. The consistent work-around is to pre-select data from the view into a temp table with the reasonable pre-filters, and then use that temp table in place of the underlying view.

  8. Create indexes on temp tables wisely. As mentioned in Tip 4, clustered indexes are usually the best in terms of performance for temp tables; however, there is a difference between creating the index before or after inserting data into the temp table. Creating the index before the insert complicates the insert, because the database engine must order the selection. For complex selections such as those mentioned in Tip 7, the extra ordering may overcomplicate the overall statement and drastically degrade the performance. On the other hand, creating the index after the insert forces the database engine to recalculate the execution plan of the stored procedure every time it is called. Therefore, the decision is always a trade-off and you should make it based on the relative costs of the two possibilities.

  9. In general, try to avoid execution plan recalculation. One common cause of recalculation occurs when the stored procedure contains several paths that depend on values passed in parameters. However, whether avoiding recalculation is possible depends on the complexity of the stored procedure and on other circumstances, such as those described in tip 8. When the engine does recalculate execution, performance always suffers; however, recalculating the execution plan of the caller does not force the execution plan recalculation of the called procedure (or view or function). Therefore, the workaround is to divide one stored procedure into multiple procedures (depending on the passed-in parameters), and then call the children from the parent conditionally. You should perform this subdivision very carefully though, because it can be a maintenance nightmare—but sometimes it seems to be the only way to achieve acceptable database performance and scalability.
Finally, although this isn't either a performance or a scalability tip, I urge you to format your stored procedure scripts legibly. It's best to agree on common practices such as clause order and formatting rules with your coworkers in advance. Not only does that help avoid errors, it also clearly shows the logical structure of the statements and often aids in figuring out faulty filters and joins.

This list of tips is certainly not exhaustive, but they probably cover the most important performance and scalability factors.

The original article could be read from the following link:
http://www.devx.com/dbzone/Article/33551/0/page/2

For an example solution (Sudoku Stored Procedure Script),  read from the following link:
http://www.devx.com/dbzone/Article/33551/0/page/3

Gene Pinski currently works as a Dev Lead at Pearson School Systems where he's responsible for several development areas of Chancery SMS in Burnaby, BC, Canada. His professional interests include developing business and web applications, and developing games. Find more about Gene from his web site.

Sunday, January 13, 2008

JavaScript Best Practices

Use Object Oriented JavaScript
• Provides better reusability of the code
• Enables your objects to be better organized
• Allow for dynamic loading of objects

Use Object Hierarchies to Organize JavaScript Objects to Avoid Name Collision
• In JavaScript there is the potential for object names to collide. In Java language, package names are used to prevent naming collisions
• JavaScript does not provide package names like Java however you can when writing components use objects and object hierarchies to organize related objects and prevent naming collision

Use the prototype property
• Use it to define shared behavior and to extend objects
• The prototype property is a language feature of JavaScript. The property is available on all objects

Write reusable JavaScript
• JavaScript should not be tied to a specific component unless absolutely necessary
• Consider not hard coding data in your functions that can be parameterized

Object Literals
• Object literals are objects defined using braces ({}) that contain a set of comma separated key value pairs much like a map in Java
• Example
{key1: "stringValue", key2: 2, key3: ['blue','green','yellow']}
• Object literals are very handy in that they can be used as arguments to a function
• Object literals should not be confused with JSON which has similar syntax

Load JavaScript On Demand
• If you have a large library or set of libraries you don't need to load everything when a page is loaded
• JavaScript may be loaded dynamically at runtime using a library such as JSAN or done manually by using AJAX to load JavaScript code and calling eval() on the JavaScript

Separation of content, CSS, and JavaScript
• A rich web application user interface is made up of
content (HTML/XHTML), styles (CSS), JavaScript
• Separating the CSS styles from the JavaScript is a practice which will make your code more manageable, easier to read, and easier to customize
• Place CSS and JavaScript code in separate files
• Optimize the bandwidth usage by having CSS and JavaScript file loaded only once

Reduce the size of JavaScript file
• Remove the white spaces and shortening the names of variables and functions in a file
• While in development mode keep your scripts readable so that they may be debugged easier
• Consider compressing your JavaScript resources when you deploy your application
• If you use a 3rd party JavaScript library use the compressed version if one is provided.
Example compression tool: ShrinkSafe

To read the actual article, you could download the pdf file from the following link.
http://www.javapassion.com/ajax/JavaScriptBestPractices.pdf

Tuesday, October 09, 2007

Cluster Computing and MapReduce

Lecture 1: Introducing Mapreduce and Cluster Computing
Distributed systems overview, review of synchronization and networking.



Lecture 2: The MapReduce programming model.
Overview of the MapReduce programming model.



Lecture 3: Distributed File Systems
Overview of distributed file systems with attention to the Google File System.




Lecture 4: Clustering Algorithms
Types of clustering algorithms, MapReduce implementations of K-Means and Canopy Clustering




Lecture 5: Graph Algorithms
Graph representations, distributed Pagerank, distributed Dijkstra.





Just as people are social animals, computers are social machines—the more, the merrier. Twenty or thirty years ago, large, centralized mainframes sat alone in sheltered bunkers in computer science departments and government offices alike, choking for hours on mere megabytes of data. Even with recent advances in server technology, large, centralized machines are still struggling to cope with today’s modern computational challenges, which now involve terabytes of data and processing requirements well beyond a single CPU (or two, or four, or eight). One computer just won’t hack it; these days, to support a new paradigm of massively parallel systems architecture, we need to break the machine out of its bunker and give it some friends.

In this age of “Internet-scale” computing, the new, evolving problems faced by computer science students and researchers require a new, evolving set of skills. It’s no longer enough to program one machine well; to tackle tomorrow’s challenges, students need to be able to program thousands of machines to manage massive amounts of data in the blink of an eye. This is how I, along with my good friend and mentor Ed Lazowska of the University of Washington’s CSE department, started to think about CS curricula and the obstacles to teaching a practical and authentic approach to massively parallel computing.

It's no easy feat. Teaching these methods effectively requires access to huge clusters and innovative new approaches to curricula. That's why we are pleased to announce the successful implementation of our Academic Cluster Computing Initiative pilot program at a handful of schools, including the University of Washington, Carnegie-Mellon University, Massachusetts Institute of Technology, Stanford University, the University of California at Berkeley and the University of Maryland. This pilot extends our expertise in large scale systems to strong undergraduate programs at the pilot schools, allowing individual students to take advantage of the hundreds of processors being made available. As the pilot progresses, we'll work with our technology partner IBM to shake the bugs out of the system so that we can expand the program to include more educators and academic researchers.

The future of computing is already taking shape on campuses today, and Google and IBM are thrilled to help inspire a new generation of computer scientists to think big. All of the course material developed by UW as well as other tools and resources to facilitate teaching this cutting- edge technology is available at http://code.google.com/edu. If you're a student wondering just what this sort of thing means for you, check out the five-part video lecture series (originally offered to Google Engineering interns) that introduces some of the fundamental concepts of large-scale cluster computing.

Earlier this year, the University of Washington partnered with Google to develop and implement a course to teach large-scale distributed computing based on MapReduce and the Google File System (GFS). The goal of developing the course was to expose students to the methods needed to address the problems associated with hundreds (or thousands) of computers processing huge datasets ranging into terabytes. I was excited to take the first version of the class, and stoked to serve as a TA in the second round.

But you can't program air, so Google provided a cluster computing environment to get us started. And since computers can't program themselves (yet?), UW provided the most essential component: students with sweet ideas for a huge cluster. After learning the ropes with these new tools, students finished the course by producing an impressive array of final projects, including an n-body simulator, a bot to perform Bayesian analysis on Wikipedia edits to search for spam, and an RSS aggregator that clustered news articles by geographic location and displayed them using the Google Maps API. Check out Geozette.

We are looking at ways to encourage other universities to get similar classes going, so we've also published the course material that was used at the University of Washington on Google Code for Educators. You're more than welcome to check out the Google Summer Intern video lectures on MapReduce, GFS, and parallelizing algorithms for large scale data processing. This summer I've been working on exposing these educational resources and other tools so that anyone can work on and think about cool distributed computing problems without the overhead of installing his or her own cluster. In that vein, we've released a virtual machine containing a pre-configured single node instance of Hadoop that has the same interface as a full cluster without any of the overhead. Feel free to give it a whirl.

We're happy to be able to expose students and researchers to the tools Googlers use everyday to tackle enormous computing challenges, and we hope that this work will encourage others to take advantage of the incredible potential of modern, highly parallel computing. Virtually all of this material is Creative Commons licensed, and we encourage educators to remix it, build upon it, and discuss it in the Google Code for Educators Forum.

Lastly, a quick shout out to the other interns who helped out on our team this summer: Aaron Kimball, Christophe Taton, Kuang Chen, and Kat Townsend. I'll miss you guys!

Resources:
http://google-code-updates.blogspot.com/2007/09/uw-and-google-teaching-in-parallel.html
http://code.google.com/edu/
http://code.google.com/edu/content/submissions/mapreduce-minilecture/listing.html
http://googleblog.blogspot.com/2007/10/let-thousand-servers-bloom.html

Friday, September 28, 2007

YouTube Scalability

This talk will discuss some of the scalability challenges that have arisen during YouTube's short but extraordinary history. YouTube has grown incredibly rapidly despite having had only a handful of people responsible for scaling the site. Topics of discussion will include hardware scalability, software scalability, and database scalability.

Speaker: Cuong Do Cuong is currently an engineering manager at YouTube/Google. He was part of the engineering team that scaled the YouTube software and hardware infrastructure from its infancy to its current scale. Prior to YouTube/Google, he held various software development and management positions at PayPal and Inktomi.




Google Tech Talks June 23, 2007

Friday, August 31, 2007

Optimize your Web site performance to survive heavy traffic

1. Avoid accessing databases to often
On a database driven content sites, the slowest task is accessing the database to retrieve the content to display. If a site is not fast enough to serve its pages, many simultaneous user accesses force the Web server to create more processes to handle all the requests.
This is bad because it demands more server memory. Once the server RAM is exhausted, the machine starts using the virtual memory, making the server even slower, until it halts completely.

2. Cache Web pages
If the site needs to access the database to retrieve the content to display, what can we do to minimize the database accesses?
First, we need to focus on what kind of information the site retrieves from databases. The most common type of data is information used to build the HTML pages.
The fact is that the information in database does not change so frequently. As a matter of fact, usually different users see the exact same HTML content when they access the same page.
It is not unusual to execute many SQL queries to retrieve all the data that is necessary to build a single HTML page. So, it is evident that it would be much more efficient if the sites could cache the HTML of each page after it is accessed for the first time.
So, what if the database content changes? Just call a code that invalidates all the page caches that depend on content of the changed database table rows. This way, it forces the caches to be rebuilt on the next access to the site pages, and so the pages are always upto date.

3. Avoid needless personalization
What about pages that appear differently to each user that accesses them? Use separate cache files depending on the user accessing the pages.
However, it would useless if the site would use a separate cache file to store the HTML that each user sees. The benefit of reusing cached information would be lost.
To maximize the efficiency of this approach you should minimize the number of user profiles that may be used for each page context. Therefore, it is very important to avoid personalization as much as you can.

4. Queue tasks that may take too long
Caching is great to avoid repeated accesses to the same content stored in a database.
However, caching only applies to accesses that retrieve data from databases. Operations that update the database content may not benefit from caching. However, when done to frequently, database write accesses may cause server overload.
One of the solution is not to update that table in real time. Instead, create a similar table that act as a queue. The queue table has no indexes. Periodically, start a background task from cron, and move the queue table data to the main table.

5. YSlow 13 optimization rules
There are many aspects to be concerned regarding what to do to make browsers interact with the Web servers in an optimized way that it takes less time and less server resources.
The issues are often not trivial to understand for people looking for quick and easy solutions to optimize their Web sites. Fortunately, there are tools that help you to audit your sites and suggest what needs to be done to boost the performance of the sites to the limit.

YSlow is one of those Web site performance auditing tools. This is a tool that the fine folks of the team of Jeremy Zawodny at Yahoo! released a few weeks ago.
http://developer.yahoo.com/yslow/

This is a wonderful tool that in a few seconds gives you an overview of how a page of your site is being served. It also suggests what can be done to optimize aspects that affect page loading speed and the consumption of Web server resources.
This tool is an extension for the Firefox browser. It works together with another very good extension named Firebug. So, to use YSlow, first you need to install Firebug.
http://www.getfirebug.com/

Once you have installed Firebug and YSlow, it is very easy to audit the performance of any Web page. Just load a Web page that you want to test and wait until it finishes loading. Then open the Firebug pane, click on the YSlow tab, and use the Performance button.

Immediately YSlow starts collecting details about the current page. When it is done it shows a list of 13 rules about aspects of the page loading performance.
On the left side of the listing you see grades from A to F. Those grades express how your page performs on each of the 13 rules, A being the best and F being the worst. On the top of the listing you see your overall "Performance Grade" also from A to F, and a score between 0 and 100.
If you got the score 100, congratulations, your page is perfect. Otherwise there is performance tuning work to be done.

Thirteen Simple Rules for Speeding Up Your Web Site are
  1. Make Fewer HTTP Requests
  2. Use a Content Delivery Network
  3. Add an Expires Header
  4. Gzip Components
  5. Put Stylesheets at the Top
  6. Put Scripts at the Bottom
  7. Avoid CSS Expressions
  8. Make JavaScript and CSS External
  9. Reduce DNS Lookups
  10. Minify JavaScript
  11. Avoid Redirects
  12. Remove Duplicate Scripts
  13. Configure ETags


6. Too much AJAX and external Javascript may kill your page performance
Using AJAX and cool Javascript libraries is definitely the latest fashion in Web application development. These are common aspects that you may notice in the so-called Web 2.0 sites.
The problem is that when you use a Javascript library that has may interdependent components, sometimes to use a simple component you end up loading a pile of separate Javascript files.

This makes the browser send a lot of requests to the Web server once it enters a page that needs many of those Javascript files. Not only it may cause excessive load to the server, but it also slows down the rendering of a page, even when the page HTML has already been fully loaded. It is a similar effect of pages that use Flash movies that take a while to load.

Browsers cache Javascript files, but when the user is making the first access to a page that needs many Javascript files, it may take too long. It may give the impression that your site is much slower than it actually is.

More detailed information regarding rules to optimize your Web site performance and for defensive programming practices to survive Web site traffic peaks can be found in www.phpclasses.org