Author |
Topic |
TexasAggie
Starting Member
9 Posts |
Posted - 2012-10-17 : 09:02:12
|
I have an application the can run in up to 20 test cells as a time, though 6 is the normal maximum. Each client writes 100-400 parameters at 1Hz using a parametrized insert statement. There is one database which contains one table for each test cell. The tables are not linked together in any way.This process works fine until I run large queries on the data. I have another program that allows users to graph, fill a table, or export to file query results from the data that is generated from these test cells. When a user performs a query that takes several seconds (I've seen 20 seconds on about 150,000 lines), the clients that are writing data lose connection since SQL does not respond.My question is how can I make this system more robust. Is it possible to do a bulk insert using the parametrized method? Should I be writing data every 60s rather than every second? Do I need to slow down the query response time? This solution is not ideal as users will not want to wait 1 minute for a result set.Any guidance will be much appreciated. |
|
sunitabeck
Master Smack Fu Yak Hacker
5155 Posts |
Posted - 2012-10-17 : 10:03:32
|
There are a number of things you can look at and may need to consider:1. Do the tables have proper indexes, so the querying will be more efficient.2. Can you pre-compute the data required for graphs and other processes so the queries can be more efficient?3. Can you make the queries more efficient? Presumably they have no cursors or while loops or anything of that nature that can kill performance4. Are the databases maintained properly? Indexes and Statistics?5. Can you use staging tables so the insertions go into staging tables, which then are periodically inserted into your main tables. In most cases, a single insertion of 100 rows into a table is more efficient than 100 insertions of one row.6. Can you partition the tables, for example based on dates so that the queries that don't need the most upto date data will not interfere with insertions.7. Can you separate the data sort of like OLTP/OLAP - perhaps even as simple as dumping the data required for analysis into a temp table and doing analysis against that. |
 |
|
TexasAggie
Starting Member
9 Posts |
Posted - 2012-10-17 : 10:43:15
|
I should first describe the architecture of the tables.Primary Key is [RowCount] which is always incrementing by 1. I use this to sort chronologically.Each test run has a RunNumber.Each RunNumber has CurrentCycle (1 to many)Each CurrentCycle has CurrentMode (1 to many)Each CurrentMode has TimeInMode (1 to many)Most queries want to return data from one RunNumber.See my comments below. Thank you for your help!quote: Originally posted by sunitabeck There are a number of things you can look at and may need to consider:1. Do the tables have proper indexes, so the querying will be more efficient.I am not proactively doing anything to index the tables. Not sure how.2. Can you pre-compute the data required for graphs and other processes so the queries can be more efficient?There is no computation in these queries. The client is simply requesting values from the table.3. Can you make the queries more efficient? Presumably they have no cursors or while loops or anything of that nature that can kill performanceThe data is returned this way: (when plotting, similar to when exporting to a txt file, etc)While (sqlRdr.Read) For Count = 0 To numSelectedChannels - 1 Values(Count) = sqlRdr.GetValue(Count) ScatterPlots(Count).PlotXYAppend(xIndex, Values(Count)) xIndex += 1 NextEnd While 4. Are the databases maintained properly? Indexes and Statistics?Again, I'm no DBA so I'm not sure.5. Can you use staging tables so the insertions go into staging tables, which then are periodically inserted into your main tables. In most cases, a single insertion of 100 rows into a table is more efficient than 100 insertions of one row.I think this is an excellent idea. I could insert data into a local (within the VB.NET client program) table and then insert the temporary table to the SQL table, dump the data, and start buffering again. Is this what you mean?6. Can you partition the tables, for example based on dates so that the queries that don't need the most upto date data will not interfere with insertions.Most queries will need more recent data. Not sure how to partition though. This is the danger of some Rambo coder getting access to a SQL database without the oversight of a good DBA. My DBA is in training..7. Can you separate the data sort of like OLTP/OLAP - perhaps even as simple as dumping the data required for analysis into a temp table and doing analysis against that.The client program will do all of the analysis.
|
 |
|
sunitabeck
Master Smack Fu Yak Hacker
5155 Posts |
Posted - 2012-10-17 : 11:35:34
|
1. You will need an index, but I don't know what columns it should be on. Can you post the query that you are using with the command object - the proper index would depend on what the query is.2. DataReader is probably the most efficient, so what you have seems fine.3. You should to update statistics on a regular basis and rebuild or reorganize indexes as required. There is some guidance on how to do this at these links - there are examples at the end of each page:http://technet.microsoft.com/en-us/library/ms187348.aspxhttp://technet.microsoft.com/en-us/library/ms189858.aspxWhatever you do, please test them in a development environment to make sure that you are not doing any harm. |
 |
|
TexasAggie
Starting Member
9 Posts |
Posted - 2012-10-17 : 12:23:43
|
quote: Originally posted by sunitabeck 1. You will need an index, but I don't know what columns it should be on. Can you post the query that you are using with the command object - the proper index would depend on what the query is.2. DataReader is probably the most efficient, so what you have seems fine.3. You should to update statistics on a regular basis and rebuild or reorganize indexes as required. There is some guidance on how to do this at these links - there are examples at the end of each page:http://technet.microsoft.com/en-us/library/ms187348.aspxhttp://technet.microsoft.com/en-us/library/ms189858.aspxWhatever you do, please test them in a development environment to make sure that you are not doing any harm.
Most queries will look like this:SELECT [RowCount],Count,[Engine Out O2],[Engine Out Smoke] FROM B142C14 WHERE RunNumber = 21 ORDER BY [RowCount]Note that I want to look at a bunch of data for one value of RunNumber. RunNumber starts at 1 in a cell and increments each time a new cycle starts. |
 |
|
sunitabeck
Master Smack Fu Yak Hacker
5155 Posts |
Posted - 2012-10-17 : 12:36:29
|
Do you have a column named COUNT? Or did you mean COUNT(*) - if it is COUNT(*) you also need a group by clause in the code. Regardless, you should try adding a non-clustered non-unique index on RunNumber column.You can create the index using the user interface in SSMS, or write a query to do it. This page has explanations and examples: http://technet.microsoft.com/en-us/library/ms189280.aspxThe syntax would be like this if you were to do it in T-SQLCREATE NONCLUSTERED INDEX IDX_B142C14_RunNUmber ON dbo.B142C14 (RunNumber ASC); Creating an index will slow down insertions and increase storage requirements, but can make queries faster. So, again, please test in a non-threatening environment to make sure that you are not doing any damage. |
 |
|
TexasAggie
Starting Member
9 Posts |
Posted - 2012-10-23 : 11:04:01
|
I have implemented the indexing.Now I want to buffer data in a table defined in VB.NET for 60 seconds before inserting into the main table.Is this the best method?Dim TempTable as TableInsert INTO TempTable blah ' 60 timesIf Count = 59 Then INSERT INTO B142C12 (Foo, Bar, Fizz, Buzz) SELECT Foo, Bar, Fizz, Buzz FROM TempTable Count = 0 Table.Clear ' Will look for the best method hereEnd If The problem with this is that I have a bunch of columns and I want them all to go. Can I use * in place of the column names?Thanks for all of your help. |
 |
|
TexasAggie
Starting Member
9 Posts |
Posted - 2012-10-24 : 11:57:50
|
After the index but before the buffering I still have the same problem. What's worse is that I try to handle it in code such that I am testing the connection state, but somehow my check does not work. Please see the code below. If SQLConn.State <> Data.ConnectionState.Open Then UseSQL = False PostMessageToStatusTab("Lost connection to SQL. Attempting to reconnect.") Dim AttemptCount As Byte = 1 Do If ConnectToSQL() Then SQLRowCount = GetSQLRowCount() BuildSQLInsertString() PostMessageToStatusTab("Successfully reconnected to SQL after " & AttemptCount & " attempts.") UseSQL = True Exit Sub Else System.Threading.Thread.Sleep(5000) End If Loop Until AttemptCount = 50 Exit Sub End If ErrorLocation = "Executing Non Query" SQLCmd.ExecuteNonQuery() Catch ex As Exception SQLErrorCount += 1 swError.WriteLine(TimeString & vbTab & "FlightRecorder" & vbNewLine & ex.ToString & vbNewLine & vbNewLine) frmD.txtMessage.Text = "Error writing SQL data!" & vbNewLine & _ ErrorLocation & vbTab & _ ex.Message & vbNewLine & frmD.txtMessage.Text If SQLErrorCount > 5 Then Try TextMessage("Error writing SQL data!") SaveError = True Catch ex1 As Exception End Try UseSQL = False End If End Try Now I have tested the ConnectionState <> Open before and it worked, but that was when I would physically disconnect the client's network connection and then plug it back in. In that case it would recover, but when I do a large query while writing data I get the following error and it does not recover. Somehow it also passes up the broken connection state. I think it must have to do with a timeout maybe?Error writing SQL data!Executing Non Query ExecuteNonQuery requires an open and available Connection. The connection's current state: Broken.The state must change to broken after executenonquery is called.SQLConnString = "Server=xx\xx;Database=yy;Integrated Security=True;Connection Timeout=30;" It should try to reconnect 5 times, and the errors occur at 1 Hz which means it isn't timing out at least on tries 2-5. |
 |
|
|