Is there any obvious performance difference between updating 1 column in a 4 column wide table vs 1 columns in a 1000 column wide table ?

  • I have a table with 4 columns and 10 million rows in which I want to update 1 column
    I have another table with 100 columns and 10 million rows in which again, I want to update 1 column.

    Which one among these 2 would perform better.

  • How many pages are in each table?

  • koustav_1982 - Thursday, December 14, 2017 12:53 PM

    I have a table with 4 columns and 10 million rows in which I want to update 1 column
    I have another table with 100 columns and 10 million rows in which again, I want to update 1 column.

    Which one among these 2 would perform better.

    Are you updating the 10 million rows?
    If the update is only to a few rows, the performance shouldn't be much different, but I suggest that you still test.
    One thing that might affect and it's more probable in a wider table is the presence of multiple indexes that contain the updated column.

    Luis C.
    General Disclaimer:
    Are you seriously taking the advice and code from someone from the internet without testing it? Do you at least understand it? Or can it easily kill your server?

    How to post data/code on a forum to get the best help: Option 1 / Option 2
  • koustav_1982 - Thursday, December 14, 2017 12:53 PM

    I have a table with 4 columns and 10 million rows in which I want to update 1 column
    I have another table with 100 columns and 10 million rows in which again, I want to update 1 column.

    Which one among these 2 would perform better.

    The question I have is why does it matter?  Presumably you're going to update both columns regardless, so does it really matter which one will perform better?

    Drew

    J. Drew Allen
    Business Intelligence Analyst
    Philadelphia, PA

  • Pure speculation and more than a couple of assumptions... The chance for a page split is higher when updating the wider table, so over time, accumulated, the update cost is going to be higher for the wider table than for the narrow one.

    However, 100 column table? Are we talking fact table or a "normalized" system? If the latter, U R DOIN IT RONG.

    "The credit belongs to the man who is actually in the arena, whose face is marred by dust and sweat and blood"
    - Theodore Roosevelt

    Author of:
    SQL Server Execution Plans
    SQL Server Query Performance Tuning

  • Impossible to say.  It depends primarily on (1) how much free space is available in each page already, (2) as noted already, how many affected indexes there are on each table.

    If the first table had no free space per page, and the second table had a lot, the first would likely be more overhead.

    SQL DBA,SQL Server MVP(07, 08, 09) "It's a dog-eat-dog world, and I'm wearing Milk-Bone underwear." "Norm", on "Cheers". Also from "Cheers", from "Carla": "You need to know 3 things about Tortelli men: Tortelli men draw women like flies; Tortelli men treat women like flies; Tortelli men's brains are in their flies".

  • I believe the answer will be that it takes less time and fewer resources to update X rows in a narrow table than it does to update the same X number of rows in a wide table because the pages being updated do have to be read and a page is the smallest amount of data that can actually be read.  So, the more narrow the table, the more rows you can fit on a page, the fewer the number of pages that will need to be read.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • There's too much speculation and little details with no further replies from the OP.

    Luis C.
    General Disclaimer:
    Are you seriously taking the advice and code from someone from the internet without testing it? Do you at least understand it? Or can it easily kill your server?

    How to post data/code on a forum to get the best help: Option 1 / Option 2
  • Luis Cazares - Saturday, December 16, 2017 12:23 PM

    There's too much speculation and little details with no further replies from the OP.

    I don't know about that, ol' friend.  If you stick only with the basics mentioned in the original post, there's no speculation required.

    I DO agree that the OP appears to have abandoned this post, though.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • Jeff Moden - Saturday, December 16, 2017 12:35 PM

    Luis Cazares - Saturday, December 16, 2017 12:23 PM

    There's too much speculation and little details with no further replies from the OP.

    I don't know about that, ol' friend.  If you stick only with the basics mentioned in the original post, there's no speculation required.

    I DO agree that the OP appears to have abandoned this post, though.

    I would still like to know how many rows would be updated, if there are indexes using that column, if it's a varying length type, etc.
    I agree with the replies, but there's nothing conclusive. Also, I don't have the intention to create a 100 column table to test. At least, not for someone else.

    Luis C.
    General Disclaimer:
    Are you seriously taking the advice and code from someone from the internet without testing it? Do you at least understand it? Or can it easily kill your server?

    How to post data/code on a forum to get the best help: Option 1 / Option 2
  • All other things being equal it will take longer to update the table with more columns. If only because there is going to be more disk IO in reading the data. Also if a table has 1000 rows it's quite likely that your updates will cause page splits, which would also slow down updates.

  • Jonathan AC Roberts - Sunday, December 17, 2017 10:12 AM

    All other things being equal it will take longer to update the table with more columns. If only because there is going to be more disk IO in reading the data. Also if a table has 1000 rows it's quite likely that your updates will cause page splits, which would also slow down updates.

    It's not just the reads from disk, which will only occur if the data isn't already cached, and testing makes it look like both a narrow and wide table will perform the same when that occurs because people forget about the eventual writes that must occur.  It's the eventual writes to disk that are the real killer even after the table is cached and most people don't measure that or take it into account in their testing.

    I absolutely agree on the page splits becoming a potentially major performance and memory issue if the update causes expansion of data in variable width columns.

    That being said, one good test is worth a thousand of our expert opinions and I'm working on a demonstration where everything is identical in two tables except one table has a CHAR(1000) column to simulate 100 additional columns.  I'll post it all soon.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • To answer the original question... no... there is no OBVIOUS difference.  You have to look for it and then you'll find that there's a huge difference. 😉

    First, here's some test data.  It makes two tables; the first (NarrowTable) only has 3 columns  and the second (WideTable) has those same 3 columns and a 4th CHAR(1000) column meant to simulate having an additional "100 columns".  The 3 similar columns in both tables are populated with exactly the same data.  There is a Clustered Index on one of the columns and it will not be the column that is updated.


    -- DROP TABLE dbo.NarrowTable, dbo.WideTable
    GO
    --=============================================================================
    --      Create the test tables and populate them with identical data.
    --      This takes about 00:01:18 on my laptop to complete.
    --=============================================================================
    --===== We don't need to measure performance for this.
        SET STATISTICS TIME,IO OFF
    ;
    --===== The "NarrowTable" contains only 3 columns and a Clustered Index
         -- to keep things as simple as the original post.
     CREATE TABLE dbo.NarrowTable
            (
             SomeID         BIGINT PRIMARY KEY CLUSTERED
            ,SomeGuid       UNIQUEIDENTIFIER
            ,SomeDT         DATETIME
            )
    ;
    --===== The "WideTable" is schematically identical to the NarrowTable except
         -- it has a CHAR(1000) column to simulate "an additional 100 columns".
     CREATE TABLE dbo.WideTable
            (
             SomeID         BIGINT PRIMARY KEY CLUSTERED
            ,SomeGuid       UNIQUEIDENTIFIER
            ,SomeDT         DATETIME
            ,SomeWideCol    CHAR(1000) DEFAULT 'X'
            )
    ;
    --===== This populates the NarrowTable with some simple data.
     INSERT INTO dbo.NarrowTable
            (SomeID, SomeGuid, SomeDT)
     SELECT TOP 1000000
             SomeID     = ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
            ,SomeGuid   = NEWID()
            ,SomeDT     = GETDATE()
       FROM      sys.all_columns ac1
      CROSS JOIN sys.all_columns ac2
    ;
    --===== This copies the exact same data from the NarrowTable to the WideTable
         -- so that we're doing the exact same test. The only difference here is
         -- the presence of the "additional 100 columns" simulated by the
         -- SomeWideCol column.
     INSERT INTO dbo.WideTable WITH (TABLOCK)
            (SomeID, SomeGuid, SomeDT)
     SELECT SomeID, SomeGuid, SomeDT
       FROM dbo.NarrowTable
      ORDER BY SomeID
     OPTION (RECOMPILE)
    ;
    --===== Flush everything to disk.
    CHECKPOINT
    ;

    Next, we have some test code.  Each table will be tested 3 times, the first of which is absolutely "cold cache" because of all the nasty DBCC stuff used just prior to starting the trilogy run for each table.  DO NOT RUN THIS CODE ON A PRODUCTION BOX BECAUSE IT DROPS ALL DATA FROM MEMORY!!!


    /*****************************************************************************/ 
    /********** DANGER!!! DO NOT RUN THIS CODE ON A PRODUCTION SYSTEM!!! *********/
    /*****************************************************************************/
    --=============================================================================
    --      Test 1: Update the NarrowTable
    --=============================================================================
    --===== Identify the test in the Messages tab.
        SET STATISTICS TIME,IO OFF;
      PRINT REPLICATE('=',80);
      PRINT SPACE(8)+'Test 1: Update NarrowTable';
      PRINT REPLICATE('=',80);

    --===== Clear all data and cache from the system.
         -- DANGER!!! DON'T EVEN THINK OF RUNNING THIS ON A PRODUCTION BOX!!!!
        SET STATISTICS TIME,IO OFF;
            CHECKPOINT;
       DBCC FREESYSTEMCACHE ('ALL');
       DBCC FREESESSIONCACHE;
       DBCC FREEPROCCACHE;
       DBCC DROPCLEANBUFFERS;
    WAITFOR DELAY '0:00:10' -- Wait for everything to "calm down".
        SET STATISTICS TIME,IO ON;
    GO
     PRINT REPLICATE('-',80)   
    DECLARE @Now DATETIME;
     SELECT @Now = GETDATE();
     UPDATE dbo.NarrowTable
        SET SomeDT = @Now;
    CHECKPOINT;
    GO 3
    /*****************************************************************************/ 
    /********** DANGER!!! DO NOT RUN THIS CODE ON A PRODUCTION SYSTEM!!! *********/
    /*****************************************************************************/
    --=============================================================================
    --      Test 2: Update the WideTable
    --=============================================================================
    --===== Identify the test in the Messages tab.
        SET STATISTICS TIME,IO OFF;
      PRINT REPLICATE('=',80);
      PRINT SPACE(8)+'Test 2: Update WideTable';
      PRINT REPLICATE('=',80);

    --===== Clear all data and cache from the system.
         -- DANGER!!! DON'T EVEN THINK OF RUNNING THIS ON A PRODUCTION BOX!!!!
        SET STATISTICS TIME,IO OFF;
            CHECKPOINT;
       DBCC FREESYSTEMCACHE ('ALL');
       DBCC FREESESSIONCACHE;
       DBCC FREEPROCCACHE;
       DBCC DROPCLEANBUFFERS;
    WAITFOR DELAY '0:00:10' -- Wait for everything to "calm down".
        SET STATISTICS TIME,IO ON;
    GO
     PRINT REPLICATE('-',80)   
    DECLARE @Now DATETIME;
     SELECT @Now = GETDATE();
     UPDATE dbo.WideTable
        SET SomeDT = @Now;
    CHECKPOINT;
    GO 3
    --===== End of test
        SET STATISTICS TIME,IO OFF;

    I've summarized the results in the following Excel spreadsheet.

    data:image/png;base64,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

    If you look at the Light Blue cells, you can see there is some little difference on the million row update for CPU usage even if you look even if you look at the first row.  Nothing obvious there.

    If you look at the Light Green cells, the two tables take turns slightly beating each other on the 2nd and 3rd run after the data has been cached but the first run takes significantly more time on the first run for the wide table because it has to load so much data.  Remember that for "Row Store" data, whole pages must be read, not just the column data you want to work with.  Still, nothing real obvious because you expect the data to be loaded in cache and used many times.

    That's were most people stop looking.

    The most obvious thing that a lot of people forget is that whole pages must be read.  Since we're updating the whole table with the test code, look at the (MB) that must be loaded into memory.  40MB compared to 1.118GB is a huge difference.  So there's difference #1.

    Because it usually occurs in the background and isn't usually measured in these types of tests, most people totally forget another measurement.  They forget that all those pages you modified, even the 100+ columns that you didn't touch, still have to be written to disk (Flushed) sometime.  If you look at the Orange cells, you'll see there's quite a difference between the amount of CPU time it takes to Flush the Narrow and Wide tables but it's still relatively trivial considering that we're working with a million rows here.  The biggest difference can be found in the Yellow cells... that the duration it takes to write all those pages to disk.  And, not listed on the spreadsheet is that all those "Reads" on the first run become "Writes" on the update runs.  That makes for a couple more no-so-obvious differences.

    Overall, it means that updating all of the rows in the WideTable takes about 9 or 10 times longer on "warm cache" runs and about 12 times longer on a "cold cache" run.

    That doesn't even include any transaction log file measurements. 😉

    Running the same tests without the Clustered Index PKs resulted in very similar run times and resource usage.

    Despite the fact that we've not explored every possibility, I'm willing to suggest that the more columns you have in your table, even for a single column update in a row store, it will make a huge difference in resource usage and overall duration virtually all the time.  I'm also not one to justify things based on possibly low row counts alone.  The same ratio of resource usage and duration will exist and I can't see wasting either just because there's a low row count if I don't need to.  As Granny used to say, "Mind the pennies and the dollars will take care of themselves". 😉 

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • Stupid new forum software doesn't allow expansion of the graphic I posted... at least not for me.  Here's something a little larger that I copied from Excel to Word and then copied from that to here. 

    Measurement

    Logical Reads

    Physical Reads

    Read Aheads

    Update
    CPU ms

    Update Duration ms

    Flush
    CPU ms

    Flush
    Duration ms

    Sum
    CPU ms

    Sum
    Duration ms

    Table

    Narrow

    Wide

    Narrow

    Wide

    Narrow

    Wide

    Narrow

    Wide

    Narrow

    Wide

    Narrow

    Wide

    Narrow

    Wide

    Narrow

    Wide

    Narrow

    Wide

    1st Run

        5,102

       143,161

    21

    363

    5,093

    143,154

    967

    1,186

    2,356

    16,925

    0

    281

    776

    19,837

    967

    1,467

    3,132

    36,762

    2nd Run

        5,102

       143,161

    0

    0

    0

    0

    905

    1,030

    1,472

    1,273

    16

    265

    642

    18,969

    921

    1,295

    2,114

    20,242

    3rd Run

        5,102

       143,161

    0

    0

    0

    0

    920

    1,076

    1,255

    1,374

    16

    203

    729

    20,969

    936

    1,279

    1,984

    22,343

    Average

        5,102

       143,161

     

     

     

     

    931

    1,097

    1,694

    6,524

    11

    250

    716

    19,925

    941

    1,347

    2,410

    26,449

    (MB)

              40

           1,118

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • Hi All

    Thanks for your replies and thanks Jeff Moden for the extensive research.

    Yes the question was related to a fact table design. 

    The background :
    In Data warehousing , in the fact table, revisions of the same record keeps getting posted , with minor changes in a few columns. Say , an order fact record has a quantity of 10 initially and then with the next revision it was updated to 20.
    We have 2 options here , 1 . to  update the same record , and 2 . to insert a new record which will save the update cost , but adds an additional cost to update the older revision with a flag - marking the record is no longer valid or to put an expiration date. 

    The first approach :
    To update , we can update the column that has changed - this adds to the cost of comparing all the columns in a fact table with the incoming record and find out what changed or update all the columns using the incoming record - both are costly operations

    The second approach : 

    To update a flag column, we have to search for an existing record in the fact table , and then update the flag / expiration date for that column. - This is what we are doing now and which is where the question comes.

    If we separate the PK and the flag to a separate table, we still have to go through the searching section to see if a record already exists, but then we come back and update a smaller table with the flag value.
    The downside is that queries on the fact table also has to join this outrigger table at run time.

Viewing 15 posts - 1 through 15 (of 27 total)

You must be logged in to reply to this topic. Login to reply