Below is my program to measure the time taken by ExecuteScalar for multiple iteration.
static void Main(string[] args)
{
string sqlConnectionString = "Data Source=.\\SQLEXPRESS;Initial Catalog=Test;Integrated Security=True";
SqlConnection connection = new SqlConnection(sqlConnectionString);
for(int i=0; i <4; i++){
Stopwatch stopWatch = new Stopwatch();
string sqlCommand = "Insert into TestTable (SNO, Name) values (" + i + ",' " + i + "')";
SqlCommand command = new SqlCommand(sqlCommand, connection);
connection.Open();
stopWatch.Start();
var result = command.ExecuteScalar();
stopWatch.Stop();
connection.Close();
Console.WriteLine("Time elapsed to insert row " + i + " : " + stopWatch.ElapsedMilliseconds);
}
Console.ReadKey();
}
Output:
Time elapsed to insert row 0 : 3
Time elapsed to insert row 1 : 1
Time elapsed to insert row 2 : 0
Time elapsed to insert row 3 : 0
My question is why it is taking 3 milliseconds for first iteration and for remaining it is lesser than that.
Thanks in advance.
This is due to Connection Pooling. Once you establish a connection (regardless of if you close it or not), as long as your connection string remains unchanged, the connections are pooled which leads to quicker consecutive executions.
Most likely the establishment of the connection which isn't really ended on close but rather returned to a connection pool and reused on the next iteration.
In general, you may also factor in query plan caching and actual data caching from the DBMS, but in this case that wouldn't really apply for INSERT operations (still, the necessary metadata for it might be cold during the first iteration).
First of all you should be using ExecuteNonQuery() method instead. Now talking about the time ; first time it has to establish the connection and then execute the query but for the later iteration that's not the case any more.
Related
Currently I am working on producing a way for ASP.NET C# web app to retrieve the highest number in a column in SQL database. Right now, I manage to produce the following line of code.
commTagNo = new SqlCommand("SELECT MAX(ComponentTagEntry) FROM dbo.HullDataSheet", connHull);
connHull.Open();
int newTagNo = (int)commTagNo.ExecuteScalar();
connHull.Close();
newTagNo = newTagNo + 1;
where connHull is the SqlConnection for above line of codes.
The above code can retrieve the highest number in column ComponentTagEntry if and only if the database already have a minimum one row of data.
If the database is empty, it will return 'Specified cast is invalid' since there are no data to do .ExecuteScalar().
What I need is, when the database is empty, for the code to retrieve the highest number as '0'.
I know that I have to modify the above code with if then statement but I don't know the value that I must compare to the true/false statement.
Any help is very appreciated.
coalesce is the way to go:
select coalesce(max(ComponentTagEntry)) from ...
For example:
create table dbo.HullDataSheet (ComponentTagEntry int);
select coalesce(max(ComponentTagEntry), 0) from HullDataSheet
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
-----------
0
(1 row(s) affected)
Table 'HullDataSheet'. Scan count 1, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
ISNULL operator should help.
commTagNo = new SqlCommand("SELECT ISNULL(MAX(ComponentTagEntry), 0) FROM dbo.HullDataSheet", connHull);
I'd suggest
int newTagNo = 0;
object testMe = commTagNo.ExecuteScalar();
if (testMe != null) { newTagNo = (int)testMe; }
Try this query. Compatible in both SQL Server & Mysql:
select
case
when MAX(ComponentTagEntry) IS NULL
then 0
else MAX(ComponentTagEntry)
end
from
dbo.HullDataSheet
I want to update my database but I think my code takes a lot of time in doing it. It takes about 20secs or more in updating. Is it possible to make it faster? If so please help me.
This is my code:
for (int i = 0; i < listView1.Items.Count; i++)
{
if (listView1.Items[i].SubItems[13].Text.ToString() == ("ACTIVE") || listView1.Items[i].SubItems[13].Text.ToString() == ("Active"))
{
for (int x = 0; x < listView1.Items[i].SubItems.Count; x++)
{
string a = listView1.Items[i].SubItems[7].Text;
TimeSpan time = Convert.ToDateTime(DateTime.Now.ToString("MMMM dd, yyyy")) - Convert.ToDateTime(a.ToString());
int days = (int)time.TotalDays;
listView1.Items[i].SubItems[11].Text = days.ToString() + " day(s)";
Class1.ConnectToDB();
Class1.sqlStatement = "Update tblhd set aging = '" + days.ToString() + " day(s)" + "'";
Class1.dbcommand = new SqlCommand(Class1.sqlStatement, Class1.dbconnection);
Class1.dbcommand.ExecuteReader();
}
}
}
It seems that you could do it with a single update statement:
UPDATE tblhd set aging=DATEDIFF(day, DateField, GETDATE())+" day(s)" WHERE ItemId=...
But it's generally not a good idea to store user-friendly labels like 'day(s)' in the database.
Actually, it is hard to say what is your SQL request suggested to do.
- Why are you using database?
- What are you storing there?
- Why are you inserting 'day(s)' string into a database instead of days integer value?
- Why are you updating ALL rows every time?
- Why are you updating (and overwriting) the same rows every time?
Please, describe your model and scenario, so, we understand how you want it work like and help you.
For your information: now your algorithm sets all rows' aging value to the last ListView's row's days value. It overwrites previously stored and recently updated data and, thus, this for loop is absolutely useless.
Each time your for loop is making a call to DB, which is not an efficient way to do this.
You can create a stored procedure which will make a single call to your DB.
do not open connection multiple time.
use using statement for connection creation using (SqlConnection
connection = Class1.ConnectToDB())
and us sql with parameter or store procedures
try to convert this day string into int so that you do not have to
convert it every time
use ExecuteNonQuery instead of ExecuteReader
I want to select data from a pipelined function in C# "just in time". That means the function pipes a row every second (like a status report) an I would like to fetch the data in C# immediately.
So far I have the following:
Oracle.DataAccess.Client.OracleConnection con = new Oracle.DataAccess.Client.OracleConnection("my_connection_string");
con.Open();
Oracle.DataAccess.Client.OracleCommand cmd = new Oracle.DataAccess.Client.OracleCommand("SELECT * FROM TABLE(MYPACKAGE.TEST_PIPELINE(10))", con);
cmd.CommandType = CommandType.Text;
Oracle.DataAccess.Client.OracleDataReader reader = cmd.ExecuteReader();
reader.FetchSize = 244; //record-size in Bytes
while (reader.Read())
{
System.Diagnostics.Debug.WriteLine("Now: " + DateTime.Now.ToString("HH:mm:ss.ffff"));
System.Diagnostics.Debug.WriteLine("ID: " + reader.GetValue(0));
System.Diagnostics.Debug.WriteLine("Text: " + reader.GetValue(1));
}
My sample function returns n (the only Function-Parameter) rows with a sleep of one second before the PIPE ROW. If I run this code I have to wait ten seconds until I get ten rows at once.
BUT if I run it a second time it works perfectly, I get one row every second (ten rows in total). Maybe just because of Statement Caching, when I add the line
cmd.AddToStatementCache = false;
I get a blocks of ten lines even at the second run.
So the question is: Anyone has an idea how to get the ten lines "just in time" (line by line every second) when I execute the code for the first time?
Thanks a lot!
Cheers
Christian
I tried to reproduce your function.
CREATE OR REPLACE PACKAGE BODY PHXDBA.PIPETEST as
FUNCTION TENSECOND RETURN TENSECOND_TT
PIPELINED AS
ctr NUMBER;
ts_ot TENSECOND_OT := TENSECOND_OT(NULL);
BEGIN
FOR ctr IN 1..10
LOOP
ts_ot.CNT := ctr;
PIPE ROW (ts_ot);
SYS.DBMS_LOCK.SLEEP(1);
END LOOP;
END;
END PIPETEST;
/
Unfortunately this always returns after 10 seconds, even in RapidSQL. So either I've implemented it wrong or the SLEEP function disrupts the piped rows coming back.
This has been bugging me for the past several hours and I can't seem to find the answer..
I have the following query
SELECT A, SUM(B) AS total
FROM table
GROUP BY A
now the column B in table can only hold 0 or 1.
and A is total1, total2 or total3
now when I use this directly in the SQL database I get a nice table holding
A total
total1 1
total2 0
toatl3 5
This is exactly what I want it to do.
However if using in my c# program. if one of the totals is 0 it is not displayed at all..
Below is the code I'm using but it only works fine when total1, total2 and total3 are bigger then 0
so the table above would only display total1 and total3...
string total = "A total";
SqlConnection conn = new SqlConnection("connection string goes here I know");
try
{
conn.Open();
SqlCommand total = new SqlCommand(
"SELECT A, SUM(B) AS total FROM table GROUP BY A", conn);
SqlDataReader total_reader = total.ExecuteReader();
while (total_reader.Read())
{
total += total_reader["A"].ToString() + " " + total_reader["total"] + "\n";
}
}
catch (Exception err)
{
serverstats += err.ToString();
}
finally
{
conn.Close();
}
How can I make it so that it would display the table properly, even if total1, total2 and total3 are 0
thus displaying:
A total
total1 0
total2 0
toatl3 0
I know that a 0 in SQL generally equals to null and such.
I suspect that this is the reason that C# assumes that if the value is 0 that it is not of interest.
I hope I explained it properly enough, thanks for any help in advance!
=======EDIT======
COALESCE or ISNULL does not make a difference :(
I assume it's to do with the C# reader bit not in the SQL querying bit.
As you can see in my example the SQL bit DOES create a table with the correct Rows and does not write them as NULL. But the C# bit seems to read it as NULL.
If column B can have nulls, try
SELECT A, COALESCE(SUM(B),0) AS total
FROM table
GROUP BY A
which sql database are you using? sql server or mysql?
or try to edit the line:
total += total_reader["A"].ToString() + " " + total_reader["total"] + "\n";
to
total += total_reader["A"].ToString() + " " + int.Parse(total_reader["total"].ToString()) + "\n";
Okay turns out that I had WHERE (B = 1)
I forgot to take this out of my SQL query..
Thanks for the help :)
StringBuilder query = new StringBuilder();
query.Append("CREATE TABLE #Codes (Code nvarchar(100) collate database_default ) ");
query.Append("Insert into #Codes (Code) ");
int lengthOfCodesArray = targetCodes.Length;
for (int index = 0; index < lengthOfCodesArray; index++)
{
string targetCode = targetCodes[index];
query.Append("Select N'" + targetCode + "' ");
if (index != lengthOfCodesArray - 1)
{
query.Append("Union All ");
}
}
query.Append("drop table #Codes ");
on: cmd.ExecuteReader() I get
There is insufficient system memory to run this query when creating temporary table
But weird thing is that, when I have 25k codes is ok, when 5k I get this error.
Initial size is 262 MB.
Lengt of each code is average 15.
This produces one giant statement, and of course it fails eventually.
You should do your INSERT one at a time (no UNION ALL), at least until it's time to optimize.
I have a feeling that your ultimate answer is going to involve BULK INSERT, but I don't know enough about your application to be sure.