Table hint on linked server query - sql-server

We have a DB2 database in AS400. Added a linked server, all went well, however occasionally the table is locked, even when we doing some select queries. Thinking about table hint in SQL Server, does the linked server query (e.g. select * from ...) support table hint?

Doubtful, but I don't know for sure.
Are you using openquery() , or 4 part names?
A query using 4 part names like so:
select * from LNKSVRNAME.IBMINAME.MYSCHEMA.MYTABLE where somecolumn = '00335';
Pulls back all the rows from MYTABLE and does the WHERE filtering on MS SQL Server.
In contrast, using openquery() like so:
select * from openquery(LNKSVRNAME, 'select * from MYSCHEMA.MYTABLE where somecolumn = ''00335''');
Sends the query to the IBM i, and only the matching rows from MYTABLE are pulled back into MS SQL Server.
If the table is being locked exclusively, there's not much you can do. However, if you're running into row locks. You may want to look at the following DB2 for IBM i clauses
FOR READ ONLY
SKIP LOCKED DATA or USE CURRENTLY COMMITTED or WAIT FOR OUTCOME
So something like this:
select * from openquery(LNKSVRNAME, 'select * from MYSCHEMA.MYTABLE where somecolumn = ''00335'' FOR READ ONLY USE CURRENTLY COMMITTED');
Note If you are actually talking to an AS/400, FOR READ ONLY is all you'll have available. But if you're talking to a relatively recent IBM POWER System running a relatively recent version of IBM i, then the concurrent-access-resolution clauses I've shown should be available.

Related

Golang SQL: More Efficient to Query Two Tables at Once or Separate Queries/Connection Pools?

I have a connection pool for database A and database B. I am moving some Node.JS code over to Go (I'm using SQL Server if that matters), and some of the queries are doing this:
db.A.Query(`
select ... from some_table;
select ... from B..other_table;
`)
Is it better to do it that way, or like:
db.A.Query(...)
db.B.Query(...)
I read this line:
create one sql.DB object for each distinct datastore you need to access
from here. And only now do I realize I read 'datastore' as 'database', so now I'm not even sure if it's efficient to have these two database connection pools!
Thank you for any help!
For most scenarios and SQL Server client programs sending multiple SELECT queries in a batch is not materially more efficient. Perhaps if the queries returned very small result sets, and you ran them at very high frequency, you could see a material difference. But in the paradigm case, whether you send the queries in one or two batches won't matter much.
It won't matter to SQL Server at all, so the only difference will be in the client/server network traffic.
SSMS will let you compare the client statistics between running queries in a one-batch script and a multi-batch script. EG running
select top 10 * from sys.objects
select top 5 * from sys.columns
and then
select top 10 * from sys.objects
GO
select top 5 * from sys.columns
in SSMS outputs the following client statistics

SSIS package Query Optimization

I would like to have idea on how to fix a minor bug identified in the program that transfers data between an Oracle Database and a SQL server Database for a web ordering systems that I support.
The issue is, when two orders are place for instance 129 and 130 on the same day, if the subsequent order (130) gets verified first, the previous web order (129) does not get moved over to the Oracle DB. This happens because that program checks for the maximum web order transferred to Oracle DB and tries to move only SQL web order numbers higher than that.
The queries built that support this concept in the SSIS package are the following:
On the Oracle Side
Select nvl(max(web_order_id),0) maxOrderIDParam from web_shipping
On the SQL Server side
SELECT cast(web_order_id as float) web_order_id, web_entry_date, site_num, protocol_num, inv_num, cast(pharm_num as float) pharm_num, status, comments, username, porstatus
FROM Web_Shipping
WHERE web_order_id > ?
AND status = 'V'
ORDER BY web_order_id
On the Oracle side
insert into web_shipping (web_order_id, web_entry_date, site_num, protocol_num, inv_num, pharm_num, status, comments, username, porStatus)
values (:web_order_id, :web_entry_date, :site_num, :protocol_num, :inv_num, :pharm_num, :status, :comments, :username, :porStatus)
On the SQL Server side
select cast(web_order_id as float) web_order_id, line_id, cast(no_of_participants as float) no_of_participants, cast(amt_inventory as float) amt_inventory, cast(NSC_num as float) NSC_num, cast(dose_str as float) dose_str, dose_unit, dose_form, dose_mult, cast(amt_req as float) amt_req
FROM web_ship_detail
WHERE web_order_id = ?
and finally on the Oracle side
insert into web_ship_detail (web_order_id, line_id, no_of_participants, amt_inventory, NSC_num, dose_str, dose_unit, dose_form, dose_mult, amt_req)
values (:web_order_id, :line_id, :no_of_participants, :amt_inventory, :NSC_num, :dose_str, :dose_unit, :dose_form, :dose_mult, :amt_req)
The effort has been to devise a resolution with minimum code change in the whole SSIS package.
I know you are looking for minimal code change not sure if these qualify but will 100% fix the problem. There are 3 options:
Modify the MS SQL table and include a "IsTransferred" bit column. When the verified record is moved to oracle, update the column to a 1/true
Keep track separate table of orders that have been transferred to Oracle. When selecting MS SQL orders exclude those that exist in the new "transferred" table.
Create a Data Flow object, with the Oracle & MS SQL orders tables as sources, use a Merge Join, using left outer. Use the results where Oracle columns are null (there is no matching Oracle records, didn't transfer) and use those records to transfer over to Oracle.
No Idea how many records are on both sides, so there may be performance concerns for some of the options.

Execute SQL task with different servers/database

Can i have my Execute SQL task look at 2 different connection manager.
For Instance: I need data from ServerA/DatabaseA querying against ServerB/DatabaseB.
So now i need to write a query and retrieve data from both servers.
Now 2 servers are not linked server, not necessarily.
Is this even possible, let me know, please.
Add a Data Flow Task with separate Data Flow Source tasks for Server A and Server B. Then join results using the appropriate Data Flow Transformation task.
As an example, this data flow takes a Flat File Source and OLEDB Source task, sorts results, then uses a Merge Join task for results. It sounds like your implementation would require two OLEDB Sources or (ODBC, ADO NET, etc.).
I like this method over the linked server or OPENROWSET, because you don't have to configure a linked server or enable Adhoc Distributed Queries on your SQL Server data sources.
I've had to find a way to work around lack of linked servers before, and I have done something like this - Give it a try:
if object_id('tempdb..#mytemptable') is not null begin drop table #mytemptable end
select * into #mytemptable
from openrowset('SQLNCLI10','Server=TheOtherServersName;Trusted_Connection=yes;','SELECT * FROM FullyQualifiedName.dbo.MyTable')
/* Now use the temptable created on this server to do your join/subquery on whatever */
select * from MyOtherTable a
join #mytemptable b on a.id = b.id
Cheers!

error when insert into linked server

I want to insert some data on the local server into a remote server, and used the following sql:
select * into linkservername.mydbname.dbo.test from localdbname.dbo.test
But it throws the following error
The object name 'linkservername.mydbname.dbo.test' contains more than the maximum number of prefixes. The maximum is 2.
How can I do that?
I don't think the new table created with the INTO clause supports 4 part names.
You would need to create the table first, then use INSERT..SELECT to populate it.
(See note in Arguments section on MSDN: reference)
The SELECT...INTO [new_table_name] statement supports a maximum of 2 prefixes: [database].[schema].[table]
NOTE: it is more performant to pull the data across the link using SELECT INTO vs. pushing it across using INSERT INTO:
SELECT INTO is minimally logged.
SELECT INTO does not implicitly start a distributed transaction, typically.
I say typically, in point #2, because in most scenarios a distributed transaction is not created implicitly when using SELECT INTO. If a profiler trace tells you SQL Server is still implicitly creating a distributed transaction, you can SELECT INTO a temp table first, to prevent the implicit distributed transaction, then move the data into your target table from the temp table.
Push vs. Pull Example
In this example we are copying data from [server_a] to [server_b] across a link. This example assumes query execution is possible from both servers:
Push
Instead of connecting to [server_a] and pushing the data to [server_b]:
INSERT INTO [server_b].[database].[schema].[table]
SELECT * FROM [database].[schema].[table]
Pull
Connect to [server_b] and pull the data from [server_a]:
SELECT * INTO [database].[schema].[table]
FROM [server_a].[database].[schema].[table]
I've been struggling with this for the last hour.
I now realise that using the syntax
SELECT orderid, orderdate, empid, custid
INTO [linkedserver].[database].[dbo].[table]
FROM Sales.Orders;
does not work with linked servers. You have to go onto your linked server and manually create the table first, then use the following syntax:
INSERT INTO [linkedserver].[database].[dbo].[table]
SELECT orderid, orderdate, empid, custid
FROM Sales.Orders
WHERE shipcountry = 'UK';
I've experienced the same issue and I've performed the following workaround:
If you are able to log on to remote server where you want to insert data with MSSQL or sqlcmd and rebuild your query vice-versa:
so from:
SELECT * INTO linkservername.mydbname.dbo.test
FROM localdbname.dbo.test
to the following:
SELECT * INTO localdbname.dbo.test
FROM linkservername.mydbname.dbo.test
In my situation it works well.
#2Toad: For sure INSERT INTO is better / more efficient. However for small queries and quick operation SELECT * INTO is more flexible because it creates the table on-the-fly and insert your data immediately, whereas INSERT INTO requires creating a table (auto-ident options and so on) before you carry out your insert operation.
I may be late to the party, but this was the first post I saw when I searched for the 4 part table name insert issue to a linked server. After reading this and a few more posts, I was able to accomplish this by using EXEC with the "AT" argument (for SQL2008+) so that the query is run from the linked server. For example, I had to insert 4M records to a pseudo-temp table on another server, and doing an INSERT-SELECT FROM statement took 10+ minutes. But changing it to the following SELECT-INTO statement, which allows the 4 part table name in the FROM clause, does it in mere seconds (less than 10 seconds in my case).
EXEC ('USE MyDatabase;
BEGIN TRY DROP TABLE TempID3 END TRY BEGIN CATCH END CATCH;
SELECT Field1, Field2, Field3
INTO TempID3
FROM SourceServer.SourceDatabase.dbo.SourceTable;') AT [DestinationServer]
GO
The query is run on DestinationServer, changes to right database, ensures the table does not already exist, and selects from the SourceServer. Minimally logged, and no fuss. This information may already out there somewhere, but I hope it helps anyone searching for similar issues.

SQL Server Linked Server Example Query

While in Management Studio, I am trying to run a query/do a join between two linked servers.
Is this a correct syntax using linked db servers:
select foo.id
from databaseserver1.db1.table1 foo,
databaseserver2.db1.table1 bar
where foo.name=bar.name
Basically, do you just preface the db server name to the db.table ?
The format should probably be:
<server>.<database>.<schema>.<table>
For example:
DatabaseServer1.db1.dbo.table1
Update: I know this is an old question and the answer I have is correct; however, I think any one else stumbling upon this should know a few things.
Namely, when querying against a linked server in a join situation the ENTIRE table from the linked server will likely be downloaded to the server the query is executing from in order to do the join operation. In the OP's case, both table1 from DB1 and table1 from DB2 will be transferred in their entirety to the server executing the query, presumably named DB3.
If you have large tables, this may result in an operation that takes a long time to execute. After all it is now constrained by network traffic speeds which is orders of magnitude slower than memory or even disk transfer speeds.
If possible, perform a single query against the remote server, without joining to a local table, to pull the data you need into a temp table. Then query off of that.
If that's not possible then you need to look at the various things that would cause SQL server to have to load the entire table locally. For example using GETDATE() or even certain joins. Others performance killers include not giving appropriate rights.
See http://thomaslarock.com/2013/05/top-3-performance-killers-for-linked-server-queries/ for some more info.
SELECT * FROM OPENQUERY([SERVER_NAME], 'SELECT * FROM DATABASE_NAME..TABLENAME')
This may help you.
For those having trouble with these other answers , try OPENQUERY
Example:
SELECT * FROM OPENQUERY([LinkedServer], 'select * from [DBName].[schema].[tablename]')
If you still find issue with <server>.<database>.<schema>.<table>
Enclose server name in []
You need to specify the schema/owner (dbo by default) as part of the reference. Also, it would be preferable to use the newer (ANSI-92) join style.
select foo.id
from databaseserver1.db1.dbo.table1 foo
inner join databaseserver2.db1.dbo.table1 bar
on foo.name = bar.name
select * from [Server].[database].[schema].[tablename]
This is the correct way to call.
Be sure to verify that the servers are linked before executing the query!
To check for linked servers call:
EXEC sys.sp_linkedservers
right click on a table and click script table as select
select name from drsql01.test.dbo.employee
drslq01 is servernmae --linked serer
test is database name
dbo is schema -default schema
employee is table name
I hope it helps to understand, how to execute query for linked server
Usually direct queries should not be used in case of linked server because it heavily use temp database of SQL server. At first step data is retrieved into temp DB then filtering occur. There are many threads about this. It is better to use open OPENQUERY because it passes SQL to the source linked server and then it return filtered results e.g.
SELECT *
FROM OPENQUERY(Linked_Server_Name , 'select * from TableName where ID = 500')
For what it's worth, I found the following syntax to work the best:
SELECT * FROM [LINKED_SERVER]...[TABLE]
I couldn't get the recommendations of others to work, using the database name. Additionally, this data source has no schema.
In sql-server(local) there are two ways to query data from a linked server(remote).
Distributed query (four part notation):
Might not work with all remote servers. If your remote server is MySQL then distributed query will not work.
Filters and joins might not work efficiently. If you have a simple query with WHERE clause, sql-server(local) might first fetch entire table from the remote server and then apply the WHERE clause locally. In case of large tables this is very inefficient since a lot of data will be moved from remote to local. However this is not always the case. If the local server has access to remote server's table statistics then it might be as efficient as using openquery More details
On the positive side T-SQL syntax will work.
SELECT * FROM [SERVER_NAME].[DATABASE_NAME].[SCHEMA_NAME].[TABLE_NAME]
OPENQUERY
This is basically a pass-through. The query is fully processed on the remote server thus will make use of index or any optimization on the remote server. Effectively reducing the amount of data transferred from the remote to local sql-server.
Minor drawback of this approach is that T-SQL syntax will not work if the remote server is anything other than sql-server.
SELECT * FROM OPENQUERY([SERVER_NAME], 'SELECT * FROM DATABASE_NAME.SCHEMA_NAME.TABLENAME')
Overall OPENQUERY seems like a much better option to use in majority of the cases.
I have done to find out the data type in the table at link_server using openquery and the results were successful.
SELECT * FROM OPENQUERY (LINKSERVERNAME, '
SELECT DATA_TYPE, COLUMN_NAME
FROM [DATABASENAME].INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME =''TABLENAME''
')
Its work for me
Following Query is work best.
Try this Query:
SELECT * FROM OPENQUERY([LINKED_SERVER_NAME], 'SELECT * FROM [DATABASE_NAME].[SCHEMA].[TABLE_NAME]')
It Very helps to link MySQL to MS SQL
PostgreSQL:
You must provide a database name in the Data Source DSN.
Run Management Studio as Administrator
You must omit the DBName from the query:
SELECT * FROM OPENQUERY([LinkedServer], 'select * from schema."tablename"')
For MariaDB (and so probably MySQL), attempting to specify the schema using the three-dot syntax did not work, resulting in the error "invalid use of schema or catalog". The following solution worked:
In SSMS, go to Server Objects > Linked Servers > Providers > MSDASQL
Ensure that "Dynamic parameter", "Level zero only", and "Allow inprocess" are all checked
You can then query any schema and table using the following syntax:
SELECT TOP 10 *
FROM LinkedServerName...[SchemaName.TableName]
Source: SELECT * FROM MySQL Linked Server using SQL Server without OpenQuery
Have you tried adding " around the first name?
like:
select foo.id
from "databaseserver1".db1.table1 foo,
"databaseserver2".db1.table1 bar
where foo.name=bar.name

Resources