THE SQL Server Blog Spot on the Web
Welcome to SQLblog.com - The SQL Server blog spot on the web Sign in | Join | Help
in Search

Aaron Bertrand

Performance / Storage Comparisons : MONEY vs. DECIMAL

As you may already know, I am not a big fan of the MONEY data type, because of its inflexibility, accuracy problems, and the expectations the name of the type evokes in new users.  If I had my way, MONEY would become a synonym for DECIMAL in SQL Server 2008 (allowing for specific precision and scale), and be removed in the following version.  Of course there are people out there that either don't feel as strongly as I do, or feel the opposite -- that MONEY should be here to stay.

After a recent discussion about the pros and cons of using MONEY vs DECIMAL for storing currency (and even non-currency) data, curiosity got the better of me.  One of the arguments for the MONEY data type was performance.  No supporting data was provided, of course.  So I decided to conduct some tests myself.  I wanted to measure how MONEY compared to DECIMAL data types both in their original implementations and using new technologies available in SQL Server 2005 (VARDECIMAL storage format) and SQL Server 2008 (page and row compression).

The person arguing for MONEY showed the space used by MONEY compared to the same information stored in a DECIMAL(20,4) column.  Not all that surprisingly, the latter was slightly larger.  But is that the whole story?  No, for two reasons.  One is that the *performance* of these choices was not compared, and the other is that DECIMAL(20,4) is not a very realistic requirement for storing currency data.  Unless you are storing the pricing information for luxury yachts or aircraft carriers, in which case you can probably drop the decimal places altogether and use INT or BIGINT.  For the rest of us, a better choice would be DECIMAL(8,2) or DECIMAL(10,2).

I created 11 databases, each with a single table containing a single column:

 

    Keeping these tables in separate databases allowed for isolation of several factors and measurements, including database level settings, log growth, data file size and even backup time.

    Next, I populated the table in each database with approximately 390,000 rows of varying length decimal data (based on calculations against object_id from a triple cross join of sys.objects on itself), and measured the insert times and storage requirements.  Here is how they stacked up:

     

    Then I performed an update that affected all rows, making sure that roughly 20% of the rows would have a significant change in significant digits (e.g. by adding 1,000,000).  Here is the performance comparison, as well as how the data and log were affected:

     

    Next I compared the time and cost of performing a SELECT COUNT(*) with a WHERE clause against the column:

     

    And finally, I performed native and compressed backups of each database, comparing execution time and output size: 

     

    The following chart summarizes everything performance-wise.  The orange with the dot means that database performed the best; the x on the red background means it performed the worst.

     

    And this chart summarizes all things size-wise: 

     

    Of course, there is nothing overly definitive here.  DECIMAL(10,2) with row compression enabled got the most "first place" metrics, while MONEY with no compression and VARDECIMAL types never finished near the top of the class.  But you can judge from the results for yourself, and make decisions based on your own priorities.

    [UPDATE]
    Alex asked for some metrics on more complex operations like SUM().  I ran some tests using both SUM() and AVG().  The logical reads of course are the same as all the others, and the scan costs remained unchanged as well.  But as for the observed performance of both calculations (compute scalar cost was identical for both operations), see the following chart:

    Again, this was an average over 10 tests.  Note that I did not append these results to the summary charts I delivered above.  And sorry about the slightly different-looking screen shot.
    [/UPDATE]

    Please take into account that these tests were performed on a dual-core laptop computer, and the database files were created on external storage. There are many other tests I could have run to glean more performance and storage data, against a much larger data set, and using production-class hardware, but for the scope of this post I just wanted to glance at the most basic operations.  I repeated these tests 10 times from start to finish, so each metric taken is an average of 10 tests (in a lot of cases they were the same every time).

    This was a very tedious exercise to perform.  If you would like to perform your own tests, with your own sample data, and on your own hardware, I will more than gladly share my scripts.  I'd post them here right now, but they are scattered and not distribution-friendly at this point. 


    Published Sunday, April 27, 2008 7:12 PM by AaronBertrand

    Comment Notification

    If you would like to receive an email when updates are made to this post, please register here

    Subscribe to this post's comments using RSS

    Comments

     

    Randall said:

    One of the reasons to prefer money is that operations on money result in money. Sometimes operations on decimal(20,4) results in decimal(38,4) or decimal(38,8) or  something even more surprising.

    April 27, 2008 6:53 PM
     

    AaronBertrand said:

    Sure, but some operations on money result in *inaccurate* results.  See the following URL for an example:

    http://tinyurl.com/59s2dn

    I agree that the rules for operations on decimal values are not very well known and sometimes downright unintuitive, but the result is obviously not as desired because the difference is visible in the result (wrong precision / scale).  With money these results can easily go unnoticed.

    April 27, 2008 7:00 PM
     

    jchang said:

    the performance overhead for decimal is quite substantial, 500-1000 additional cpu cycles per row & column for the conversion.

    I believe money is just bigint offset by 4 decimal places

    April 27, 2008 7:41 PM
     

    AaronBertrand said:

    Joe, at least in these tests in both SELECT and WHERE, CPU performance according to actual plan was identical across all the datatypes used.

    April 27, 2008 8:02 PM
     

    Alexander Kuznetsov said:

    Hi Aaron,

    This is very interesting, thanks! Would you mind comparing performance of more complex calculations involving these numbers, such as SUM().

    April 27, 2008 8:30 PM
     

    AaronBertrand said:

    Thanks Alex, I have added a chart showing the performance of the following queries:

    SELECT SUM(i) FROM dbo.Test WHERE i BETWEEN 200000  AND 370000;

    SELECT AVG(i) FROM dbo.Test WHERE i BETWEEN 200000  AND 370000;

    The result is a little surprising to me, but I can't dispute what I observed.  :-)

    April 27, 2008 9:22 PM
     

    Jason Haley said:

    April 28, 2008 10:09 AM
     

    Jason Haley said:

    April 28, 2008 10:10 AM
     

    Alexander Kuznetsov said:

    Hi Aaron,

    This is indeed surprising. Thank you again for writing it up!

    April 29, 2008 10:32 AM
     

    AaronBertrand said:

    Sure.  I am working on a much larger example (~30GB databases) and would welcome any input you have on calculations that should be performed... I think the small data size (and therefore sub-second execution times) does not accurately reflect what would happen in a real-world scenario.

    April 29, 2008 11:25 AM
     

    jchang said:

    the above results are accurate for in-memory ops, which is why i said decimal is not cheap, like i said in my execution plan blog, the plan cost is for determining the table access strategy, not the additional logic cost, consider the plan and true cost for SELECT SUM(col1) FROM xx, against SELECT SUM(col1), SUM(col2) FROM xx and so on. the only thing that is different in 30GB the disk access patterns, which i will write about later

    April 29, 2008 6:06 PM
     

    Datatypes said:

    hubs about Datatypes to As you may already know, I am not a big fan of the MONEY data type , because of its inflexibility, accuracy problems, and the expectations the name of the type evokes in new users. If I had my way, MONEY would become a synonym

    May 11, 2008 10:12 PM

    Leave a Comment

    (required) 
    (optional)
    (required) 
    Submit
    Powered by Community Server (Commercial Edition), by Telligent Systems
      Privacy Statement