views:

461

answers:

7

I am writing an application that logs status updates (GPS locations) from devices to a database. The updates occur at a set interval for each device, which is currently every 3 seconds. I'm using a simple table in SQL Server 08 for storing each update.

I've noticed that running the inserts is an area of slow down in my application. Its not a severe slow down, but noticable. Naturally, I'd like to write to the database in as an efficient way as possible. I have an idea to improve the performance and am looking for input and advice to see if it will help:

The status updates come in from an asynchronous Socket thread. In my current implementation, the database insert call is executed from this thread. I'm thinking I can create a queue for holding update data that the Socket thread can quickly add its update to and then go on its merry way. There would then be a separate thread whose sole responsibility would be checking the update queue and inserting the updates into the database.

Basically this whole process rests on the assumption that writing to the database from one location with a bunch of data all at once is more efficient than writing one row of data at a random time. Is my assumption correct, or way off base? Also, on the SQL side, is there a command to tell it to write a bunch of rows at once that would improve write performance?

This is how the database is being written to:

I'm using LinqToSQL in C#, so for each insert, I first create a DataContext instance. From the DataContext object I then call a stored procedure which inserts the location update. The table is indexed by datetime, for the time of the update.

+1  A: 

Have you looked MSMQ ( Microsoft Message Queuing (MSMQ)) ? That seems to me an option to take a look.

J.W.
MSMQ would defer the problem because it is asynchronous (and disconnected), but it sounds like there's a bottleneck that could cause capacity problems in the future. Switching to asynch writes only paints over this underlying problem.
Michael Meadows
A: 

Another area you might want to take a look at is whether you are setting up and tearing down a connection for each insert. That alone might make a performance improvement, negating the need for batching.

You'll also want to have as few indexes on the table as possible.

hova
This sounds like a good point. I'm currently using a LinqToSql DataContext for the database stuff. I'll have to look into the specifics, but I imagine there's a couple ways there that I can optimize the connection.
grimus
A: 

It sounds like a good idea. Why not give it a shot and see how it performs?

RibaldEddie
A: 

On the SQL side you'd want to have a look at making sure you are using parameterized queries.

Also batching your INSERT statements will certainly increase the performance.

Connection management is also key, of course that depends on how the application is built and whether it depends on a connection being there.

Mat Nadrofsky
+1  A: 

Yes, inserting in batches will typically be faster than separate inserts given your description. Each insert will require a connection to be set up and packets to be transferred. If you have a single small insert that takes one packet and you issue three of those, but you alternatively have three inserts that are small enough that they can all fit in one packet then it will help.

Quantifying it is difficult just based on your description - you'll need to do testing for that. For example, if you are keeping a dedicated connection open at all times anyway, as hova suggests, then you might see less of an impact.

Tom H.
+2  A: 

Have a look at the SqlBulkCopy class - this allows you to use BCP to insert chunks of data very quickly.

Also, make sure your indexes are efficient. If you have a clustered index on anything that does not increase sequentially (integer, date) then you will suffer performance slowdowns as the pages are filled up.

ck
@ck, you hit my two points. Queue the writes and write them in batches using SqlBulkCopy, and make sure your indexes are created correctly. SQL Profiler will help with the latter. Also, if indexes are the problem, you can write to a staging table and batch update (at low volume times).
Michael Meadows
A: 

Are you not afraid to loose data while are you collecting data to batch copy?

I'm writing application doing the same. At start I will have to write data from 3,5k GPS devices. One device should send data each minute but it can send faster. Destination number of devices is 10,5k.

I'm wondering about inserting performance too. For now I'm saving received data to db on every packet using pure ADO.NET ICommand and stored procedure. On my test serwer (Xeon 3,4GHz and one 1TB hard disk - normal desktop ;) it takes for now 1ms or less.

@GRIMUS - should I wondering if there will be more devices?

dario-g