Here is a rather vanilla fast table load destination using SSIS data flow task. Notice how I have Rows per batch=200,000 and Maximum insert commit size=200,000. You might expect that the fast load will insert about 200,000 rows per batch and transaction. You would be wrong, as it is also gated by the buffer size of the data flow task. To determine how many rows are being inserted per batch/transaction, simply use SQL Profiler and trace the INSERT BULK commands. They are simply SQL:BatchCompleted events. To see the number of rows, look at the RowCounts column in the trace. It will probably be a little less than 10,000.
Sunday, December 14, 2014
High Performing Big Table Loads in SSIS
Here is a rather vanilla fast table load destination using SSIS data flow task. Notice how I have Rows per batch=200,000 and Maximum insert commit size=200,000. You might expect that the fast load will insert about 200,000 rows per batch and transaction. You would be wrong, as it is also gated by the buffer size of the data flow task. To determine how many rows are being inserted per batch/transaction, simply use SQL Profiler and trace the INSERT BULK commands. They are simply SQL:BatchCompleted events. To see the number of rows, look at the RowCounts column in the trace. It will probably be a little less than 10,000.
Sunday, March 13, 2011
(re) Clustering a Large Online Table
- Create the new table with the clustered (and non clustered) indexes you want.
- Create a control table to maintain high-low watermarks. Set the high water mark to the maximum ascending key value in the live table.
- Perform a bulk load (SSIS Data Flow task) for all the live table rows up to and including the high water mark. This task might take several hours.
- Set the low water mark to the high water mark, then re set the high water mark to the new maximum ascending key value in the live table.
- Perform the bulk load again. This time it will just be the rows that have been inserted during our earlier bulk load. After this task, the new table will be very close, but not quite, up to date to the live table.
- Within the scope of a transaction lock the live table, insert records above the high water mark, rename the tables (and PKs) and commit the transaction. The new table is now live.
A few notes on the process
- You will need to have sufficient space in your database to accommodate two copies of the table.
- You will need to have sufficient space in your database logs to hold log records from the start of the Main Bulk Load to the end of the Main Bulk Load. So, if the bulk load takes 4 hours, their will be a transaction open for 4 hours and a log truncation won't truncate anything within the 4 hours.
- You will need to have sufficient space in tempdb to perform the sorts for the clustered index and nonclustered indexes.
- If you have sufficient space in the database files and logs, you should set the maximum commit size on the destination to 0 (zero). Having other values will tend to slow down the load process (although less disk space is required) since the indexes will be maintained at each commit.
- It is quite likely that your large tables are partitioned and compressed. This doesn't need to make any difference to the reclustering process above. However, if the table is already partitioned, you could improve performance by looping through each partition. If your table isn't already partitioned, this process could be the opportunity to partition your table.
- Don't be tempted to use NOLOCK when reading the live table.
- Test your package before you run it in production.
There is no special code in the package I have created. The most significant task is the very last one, which is performed within the scope of a transaction. To ensure there is no opportunity of a deadlock, the task first asks for an X lock on the live table. Here is some sample SQL from each of the tasks.
Create Control table
create table ReclusteringControl( ReclusteringControlID int default 1, LowWater bigint not null default 0, HighWater bigint not null default 0, CONSTRAINT [PK_ReclusteringControl] PRIMARY KEY NONCLUSTERED (ReclusteringControlID ASC))
Insert into ReclusteringControl values(1,0,0)
update ReclusteringControl set HighWater=(select max(rid) from MyLargeTable)
Input for Main Bulk Load
select * from MyLargeTablewhere rid<=(select HighWater from ReclusteringControl)
Set New HighWatermark
update ReclusteringControl set LowWater=HighWater
update ReclusteringControl set HighWater=(select max(rid) from MyLargeTable)
Second Bulk Load (input statement)
select * from MyLargeTablewhere rid<=(select HighWater from ReclusteringControl) and rid>(select LowWater from ReclusteringControl)
Final INSERT and Rename
--set identity_insert MyLargeTable_new on
--This is required if there is an identity column on the table
GO
begin transaction
update ReclusteringControl
set LowWater=HighWater
select top 0 * from MyLargeTable with (tablockx)
update ReclusteringControl set HighWater=(select max(rid) from MyLargeTable)
insert into MyLargeTable_new --columns need to be explicitly declared if identity cols are inserted
select * from MyLargeTable where rid<=(select HighWater from ReclusteringControl) and rid>(select LowWater from ReclusteringControl);
exec sp_rename MyLargeTable,XXXX_MyLargeTable;--should delete this table
exec sp_rename MyLargeTable_new,MyLargeTable;
exec sp_rename PK_MyLargeTable, PK_MyLargeTable_XXXX
exec sp_rename PK_MyLargeTable_new, PK_MyLargeTable
commit transaction
--set identity_insert MyLargeTable off
Monday, February 15, 2010
SSIS Slowly Changing Dimension SCD Wizard is Too Slow
Hence if you have large volumes of data and need to have high performing SCD updates, you will need to use a batch update statement. This is not all that difficult. I would even suggest that if you can't write the SQL, you might not the be the best person to design a DW.
Essentially, you need to "close off" the records that are getting replaced, and "insert" all new records. The "closing" of records can be done in a single UPDATE statement as shown in the query below. Note, the exact script you need will depend on your SCD and non-SCD attributes and the format of your source data. But essentially, you are updating all records in the DW where there exists a newer record. If you have some Type 1 attributes, will need another update statement for them.
The second task is simply to insert the new (and updated) records. You should do this in an SSIS data flow task. The select statement in the image below, is an example of what the query will look like to feed that load. Note, your query will be a little different depending on how you identify changes, but the query below will give you a starting template.
By the way, if you really don't want to write the above queries (or prefer the elegance of a component) there are 3rd party SSIS components that manage SCD with set based operations.
Of course, I am sure a future version of SQL Server will have an SCD wizard that works with batch update commands. Just not sure which one.
Friday, January 15, 2010
The Transaction Manager is not available
- These error messages are, in essence, telling you that DTC cannot communicate with SQL Server. Here's what you need to check
Ensure both computers can ping each other using netbios names. Netbios names must be used for DTC transactions. - Both computers must have MSDTC running
- If there are firewalls on either machine, they must have exceptions for Port 135 or for the program msdtc.exe.
The dtcPing tool can be helpful in diagnosing DTC issues. For more information see http://support.microsoft.com/kb/918331
Now, whether or not you want to use large scope transactions is another question, and not a simple one to answer. A couple of points to think about when you are considering using transactions are
- Any update, insert etc to a rdmbs is either completed successfully or rolled back. Using TransactionOption "Required" as I discuss above is about combining many update/insert/delete statements so that they all succeed or none of them do.
- Be mindful of how long the transaction runs for. This is the time that another transaction might have to wait if there is a locking issue.
- There might be other ways to ensure your data integrity. For example, if you are thinking about transactions to enable simple re-running of the package in the event of an error, you might be able to structure the package so that it can re-run even after successful completion of some, or all, of the tasks.
Another point worth noting with SSIS transactions is that you can set TransactionOption of "Required" on the package, and have a task (such as Execute SQL) which has a TransactionOption of NotSupported. In this way, so long as the tasks executes, it will not be rolled back with the rest of the package in the event of a failure.
For a real-time demonstration of data that has SSIS packages loading/processing about 300 new records/second (all day, every day) see http://RichardLees.com.au/sites/Demonstrations
Wednesday, July 1, 2009
Restartable or Rerunnable SSIS Packages
For example, my Permon application (Perfmon Dashboard) has a job that runs every 180 seconds to transform and load the new records, and incrementally process the OLAP cube. Every now and again the machine is restarted for some reason and the Perfmon update process could be at any point when it is stopped. However, the job will automatically run from the right place, next time it runs. It will know whether there is 3 minutes or 10 minutes of data to process, by using high water marks in the database. In this way, I have no operational overhead in running this application. It just looks after itself. It is the same for the weblogs BI solution on Weblogs Dashboard. If your BI solution requires manual intervention after a failure or an error, get someone else in, like myself, to fix it up to run automatically without manual intervention.
Now having said that, it is often useful to be able to pass parameters to an SSIS package. (I just needed to mention automatically correcting jobs above, as some developers make packages restartable,to help with manual correction, when it should be automatic.)

