views:

24

answers:

2

Some years ago I built an Excel file for my colleagues that displays lots of data from an external ODBC data source. The data is partitioned into lots of data tables in different sheets. The file also contains a button that allows the user to update the data.

Since accessing the data from the external source was very slow, I implemented some caching logic that stored parts of the results, that were unlikely to change, in external tables on our SQL server and did some magic to keep the data synchronized. The excel file itself only accesses the SQL server. Every data table uses an SPROC to get part of the data.

Fast forward 5 years. The Excel file has grown in size and contain so many sheets and data that our Excel (still version 2003) got problems with it. So my colleagues split the file into two halfs.

The problem is now, that both excel files contain the logic to update the data and it can happen that a user clicks the update button in file no. 1 while another user is already updating file no. 2.

That's the point where the updating logic goes berserk and produces garbage.

The update run is only required once for both excel files because it updates all the data that's displayed in both files. It's quite expensive and lasts from 5 to 15 minutes.

I could split the update run into two halfs as well, but that wouldn't make it any faster and updating the two files would take twice as long.

What I think about is some kind of mutex: User A clicks on the update button and the update run starts. User B wants to update too, but the (VBA/SPROC) logic detects that there's already an update running and waits till it finishes.

+1  A: 

You could perform the updates in a Transaction with Serializable isolation level; your update code would need to detect and handle SQL Server error 1205 (and report to user that another update is in process).

Alternatively, add a rowversion timestamp to each row and only update a row if it hasn't been changed since you loaded it.

Mitch Wheat
+1  A: 

But when A has finished, B will run the update 'for nothing'.

Instead: When A clicks update, call a stored proc which fires the update asynchronously. When the update starts, it looks at the last time it ran itself and exits if it was less than X minutes ago.

smirkingman