Timeout error in running a multi-server SQL Server query - c#

I defined a linked server to a remote server in my local SQL Server.
I run a query in join of local and remote servers as below:
SELECT *
FROM [RemteServer].[RemoteDB].[dbo].[Links]
WHERE Id NOT IN
(
SELECT ExternalId
FROM [dbo].[Links]
)
When I run this query on SQL Server Management Studio, It executes during 2 minutes, but when I run it on a C# program on my local machine connected to local SQL Server it produces timeout error.
I set connect timeout on C# connection string to 600. also I set Connection timeout and Query timeout on Linked Server properties to 600.
How can I prevent timeout error?
P.S: SQL server version is 2008. I use Visual Studio 2015 and use ADO connection on VS.

My recommendation would be to migrate the bulk of this query onto the SQL Server, and use a stored procedure to do the work.
SQL Server
CREATE PROCEDURE dbo.lsp_GetRemoteLinks
AS
BEGIN
IF OBJECT_ID('tempdb..#RemoteLinks') IS NOT NULL DROP TABLE #RemoteLinks
SELECT *
INTO #RemoteLinks
FROM [RemteServer].[RemoteDB].[dbo].[Links]
SELECT *
FROM #RemoteLinks
WHERE (Id NOT IN (SELECT ExternalId FROM [dbo].[Links] ))
DROP TABLE #RemoteLinks
END
GO
C#
DataTable RemoteLinks = new DataTable();
using (SqlConnection conn = new SqlConnection(strConn)) {
conn.Open();
using (SqlCommand cmd = new SqlCommand("lsp_GetRemoteLinks", conn)) {
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandTimeout = 120;
RemoteLinks.Load(cmd.ExecuteReader());
}
conn.Close();
}
This should cut your times down, but I did put increase the CommandTimeout value.
If this data did not need to be "live" with it's freshness I would consider making a permanent local table and use SQL Agent to re-populate it at regular intervals, and then you would be able to use Indexes on the table to improve efficiency further.

Your performance on this query is not ideal because you are essentially trying to read every record from the Linked server onto your Local server where the query is being executed. If you can filter the results by adding a WHERE clause that will be executed on the remote server, your performance will significantly improve.
DECLARE #ExtLinks TABLE (Id INT)
INSERT INTO #ExtLinks (Id)
SELECT ID
FROM [RemteServer].[RemoteDB].[dbo].[Links]
--WHERE Princess = 'Zelda'
SELECT * FROM #ExtLinks
WHERE Id NOT IN
(
SELECT ExternalId
FROM [dbo].[Links]
)

Related

Why is SQL Server Database User Writing to the Wrong Schema?

In my database, I have 2 schemas: [dbo] and [rch] ([rch] was selected as the name for our "archived" data so that those tables would not appear before the [dbo] tables).
I created a user for this table called rchuser in SQL Server Management Studio (SSMS):
Notice above that the user is added with rch listed as the Default Schema.
Notice above that this new user owns both db_owner and rch.
Let's say I have this SQL insert:
public static int AddRecord(object value, string sqlConnection)
{
int result = 0;
using (var conn = new System.Data.SqlClient.SqlConnection(sqlConnection))
{
conn.Open();
var sqlCmd =
"INSERT INTO Table1 ([Value], [Stamp]) " +
"VALUES (#Value, GETDATE()); ";
using (var cmd = new System.Data.SqlClient.SqlCommand(sqlCmd, conn))
{
cmd.Parameters.AddWithValue("#Value", value);
result = cmd.ExecuteNonQuery();
}
}
return result;
}
I passed that method a connection string using my rchuser credentials.
var conn = "Data Source=localhost;Initial Catalog=DatabaseN;User Id=rchuser;Password=password;"
There is no error, result is 1, but the new record is NOT in the corresponding table for my [rch] schema.
It is like the database is completely ignoring the fact that this user defaults to the [rch] schema.
I even tried logging into the SSMS database with rchuser to execute the command by hand. Again, no errors. The data went into [dbo].
How do I direct all database input to go to another schema?
If you have multiple schemas in a database, then my recommendation is to always explicitly specify which one you want. Aaron Bertrand has a good article on why you should do it, even if you only have one schema.
So modify your sql statement to be
INSERT INTO [rch].Table1...
and you will be all good.
I do note that this doesn't answer your title, but it does answer your question.
As to why your query isn't defaulting to the [rch] schema, I don't know. I replicated your setup in SQL Server 2008 R2, and when I run your original query then the inserts do go into the rch table as expected.
EDIT:
I did some Googling, and I suspect that your problem is caused by granting the sysadmin server role to the rchuser login. I modified mine to be an sa
, and now the inserts go into the [dbo] schema by default, even though rchuser has a default schema of [rch].
So, if you remove the sysadmin server role, it should start working as expected.
Have You tried to specifiy schema for table in Your query?
var sqlCmd =
"INSERT INTO rch.Table1 ([Value], [Stamp]) " +
"VALUES (#Value, GETDATE()); ";

Synchronize Data from serverDB to Local DB

I would like to get all the details of a single table from Remote server DB to my local DB, during page load event which should happen as a back end process can any one help me over this issue.
NOTE:
Server DB table Columns may slightly differ from local DB.
Each time when a new user is added in the server, it should update the local DB when the UserPage.aspx page is loaded.
Tools using: ASP.NET,SQL SERVER 2008.
Eg: Let the DB name be sample and the table name is customer
**Table Header in Server DB:** Cus_id,Cus_name,Cus_address,Cus_email,Cus_mob
**Table Headers in Local DB:** Cus_id,Cus_name,Cus_address,Cus_email,Cus_mob,Cus_password
Once the page gets loaded all the data in Customer table from serve DB should be synchronized to localDB
Asuming that the database login has access to both db's you can execute the following string as one command through your database connections.
--empty local table
truncate table [sample]..customer;
--fill local table
insert into [sample]..customer
(Cus_id,Cus_name,Cus_address,Cus_email,Cus_mob)
select Cus_id,Cus_name,Cus_address,Cus_email,Cus_mob from serverDb..Customer;
This will get you startet, but this is not good architecture. You might want to put a trigger on the table in the server database that will insert the new row in your local database everytime there is a new row in the serverDb.
edit
showing the whole process
protected void Page_Load(object sender, EventArgs e){
string sql = #"--empty local table
truncate table [sample]..customer;
--fill local table
insert into [sample]..customer
(Cus_id,Cus_name,Cus_address,Cus_email,Cus_mob)
select Cus_id,Cus_name,Cus_address,Cus_email,Cus_mob from serverDb..Customer;";
var conn = new SqlConnection("Server=localhost;Database=sample;User Id=myUserName;Password = myPassword");
var cmd = conn.CreateCommand();
cmd.CommandText = sql;
conn.Open();
cmd.ExecuteNonQuery();
}
I will advice you SCHEDULE a job to load record to localdb from the backend every 15mins interval. You can use management studios to achieve that.

No data return If search condition of a select query contains only numerals and query on a nVarChar column of a table

I have windows application to synchronize data of a windows mobile application stored in a SQL Server CE database. I got a few issues on synchronization of mobile connected to windows 7 32bit PC.
On synchronization, windows application will copy the SQL Server CE database from Mobile Device to the PC and do synchronization of data with locally copied database then copy back to the Mobile Device. If the PC which done synchronization is a windows 7 32Bit then I'll get following issues in Windows Mobile Application when working with synchronized database.
If there is a table with nVarChar columns and do search query on that column, no data will return if search condition contains numerals with single quotes to indicate value as a string (in following example strProductID is a nVarchar column)
eg:-
SELECT * FROM Products WHERE strProductID = '2345'
But numerals without quotes or alpha with quotes will works fine
eg:-
SELECT * FROM Products WHERE strProductID = 2345
or
SELECT * FROM Products WHERE strProductID = 'asdasd'
As Aaron Bertrand has stated in the comment, your queries will work much better if you use Parameters.
How large is the strProductID NVARCHAR field? 50? I'm going to assume 50 so I can write your parameterized query:
private DataTable Get(string strProductID, string connStr) {
var table = new DataTable();
string cmdText = "SELECT * FROM Products WHERE strProductID=#strProductID";
using (var cmd = new SqlCeCommand(cmdText, new SqlCeConnection(connStr))) {
cmd.Parameters.Add("#strProductID", SqlDbType.NVarChar, 50).Value = strProductID;
cmd.Connection.Open();
table.Load(cmd.ExecuteReader());
cmd.Connection.Close();
}
return table;
}
However, Microsoft has admitted that Disconnected Datasets are not very reliable in Windows Mobile devices! See the comments in the Walkthrough: Creating an Occasionally Connected Smart Device Application.

Creating a database connection for every database insert - High SQL server memory usage

I have recently changed my web app to create a database connection per command instead of creating one connection and just reusing it for all commands. I used this code this afternoon and my database memory went up to 24GB usage peforming about 8k inserts. My code is like this (semi pseudo code):
public int ExecSQL(string SQLStr)
{
using (SqlConnection Con = new SqlConnection(MyConStr))
{
using (SqlCommand Cmd = new SqlCommand(SQLStr, Con))
{
return Cmd.ExecuteNonQuery();
}
}
}
using (TransactionScope TX = new TransactionScope(TransactionScopeOption.RequiresNew))
{
//Loop and perform 8000 x
int ID = ExecSQL("insert into something (column) output unique_id values ('data')").
// I also perform 1 or 2 selects per insert based on the ID returned from the insert. I don't use a .Supress for my inserts.
}
Could this of caused the high database memory usage? I was under the impression it should create 100 connections (default) then just keep re-using it but I am guessing I am missing something.
Answered: Ran the following SQL:
SELECT
DB_NAME(dbid) as DBName,
COUNT(dbid) as NumberOfConnections,
loginame as LoginName
FROM
sys.sysprocesses
WHERE
dbid > 0
GROUP BY
dbid, loginame
and there is only one open connection for my database so this isn't causing the issue. Now to find out what is ..
ADO.NET uses connection pools, so multiple SqlConnection objects with the same connection strings reuse the same physical database connection. Hardly your memory increase was caused by using new SqlConnection()

C#: DB2 test available connection first

I have a C# .NET program running an ETL which connects to a DB2 database. Sometimes this database is down, so I'd like to do a health check at the beginning of the application to see if the database is available, without actually calling any stored procedures or pushing any data. Here's an example of the code I'm using now:
OdbcConnection myODBCConnection = new OdbcConnection("DSN=DB2AA;UID=ABCD;PWD=1234;");
OdbcCommand myODBCCommand = new OdbcCommand();
myODBCCommand.CommandType = CommandType.StoredProcedure;
myODBCCommand.CommandText = "{CALL SYSPROC.ABC001(?, ?)}";
myODBCCommand.Parameters.Add("INPUT", OdbcType.VarChar, 500);
myODBCCommand.Parameters["INPUT"] = myString
myODBCCommand.Connection = myODBCConnection
myODBCConnection.Open();
OdbcTransaction myTrans;
myTrans = myODBCConnection.BeginTransaction();
myODBCCommand.Transaction = myTrans;
myTrans.Commit();
myODBCCommand.ExecuteNonQuery();
myODBCConnection.Close();
What's the best way to test this connection without actually pushing any data?
You can simply run some innoccuous select query to check to see if the db is available.
You can try to do something as simple as:
Select 1
Or
Select getdate()
Those simple queries don't even touch any tables but will return only if the rdbms is running.
Note: those examples are for sql server but might work for db2. I haven't had to do a live check on a db2 yet though the similar concept should be doable.
Note 2: after a closer look at your code, all you should really have/need to do is check for success of your odbc connection's .Open() call.

Categories