We are working on SQL Server 2008. Java web application is used as the front end.
Each query that gets fired from application is executed as a stored procedure as shown in query #1.
We observed while executing simple SELECT and UPDATE query from application execution plan is different.
Query #1 takes 3 secs for execution:
declare #p1 int
exec sp_prepexec #p1 output, N'#P4 nvarchar(4000)',
N' SELECT KEY FROM dbo.DETAIL
WHERE KEY = #P4',N'SIND-60068635-R-202'
select #p1
Query #2 takes less than 1 sec for execution:
SELECT KEY
FROM DETAIL
WHERE KEY = 'SIND-60068635-R-202'
We observed execution plan for both queries are different. For 2nd query an index created on KEY is getting applied and hence query response is good, but that same index is not getting used for query #1, and hence query response time is bad.
Any suggestion how to fix this issue are appreciated.
Yes,There’s a problem, When we switch over to using a parameter in Stored Procedure, SQL Server isn’t able to make effective use of the filtered index. To resolve this issue one way is to use Index Hint like
SELECT * FROM <Table> WITH (INDEX(<indexName>))
but for that we have to keep using the same index name
Other way is to use string concatenation i.e. by forcing SQL Server to see the literal value (parameter)
e.g.
DECLARE #sql AS NVARCHAR(MAX) = N'';
DECLARE #p1 AS VARCHAR(10)='test'
SET #sql += 'SELECT KEY FROM dbo.DETAIL WHERE KEY = ' + CAST(#p1 AS NVARCHAR(10));
EXEC sp_executesql #sql;
Visit this url
- https://www.brentozar.com/archive/2013/11/filtered-indexes-and-dynamic-sql/
By changing nvarchar to varchar has helped for getting performance benefit (index scan to index seek). Also as JDBC is creating this issue while passing parameters as nvarchar instead of varchar . We referred following blog
https://blogs.msdn.microsoft.com/sqlcat/2010/04/05/character-data-type-conversion-when-using-sql-server-jdbc-drivers/
Related
I'm painfully new to SQL/mySQL as a whole so I'm flying blind right now so apologies.
I made a procedure in mySQL that selects a varchar data from a specific column and table, turn it into INT (contents of said column are numerical to begin with) and output its values after going through a mathematical operation as a (very simple) attempt in data masking. As follows:
CREATE PROCEDURE qdwh.mask_varchar_num2(tablename varchar(100), colname varchar (100))
BEGIN
set #a=concat('select','(','(','(','(','select',colname ,'from',tablename,')','+','0',')','+','297',')','*','5',')','as','colname');
prepare query from #a;
execute query;
deallocate prepare query;
END
but when i tried to call the procedure with the following line:
select [column] , mask_varchar_num2 ([column]) from [table];
an error "FUNCTION qdwh.mask_varchar_num2 does not exist" shows up. I wanted the script to output a select function of the column in question after the conversion to INT and the mathematical operation done to it, so i can then use this procedure in a larger script ("create table select as" kinda stuff) to convert the whole table into masked data as needed.
Is there something i am missing and what am i doing wrong? Dbeaver acknowledges the procedure script as legit so i dont know whats wrong. Thanks in advance for the advice.
Procedures are run by using call and cannot be called within a select query. To define a function, you need to use create function.
not an answer but here's what your select looks like..
set #colname='a';
set #tablename='t';
set #a=concat('select','(','(','(','(','select',#colname ,'from',#tablename,')','+','0',')','+','297',')','*','5',')','as','colname');
select #a
'select((((selectafromt)+0)+297)*5)ascolname'
missing a lot of spaces between tokens
I have a problem where it seems that when running the same stored procedure at the same time from two different instances of the same application it is timing out, and wondered if there was anything I could do to resolve it?
I believe the problem is in the way SQL Server 2008 handles itself, locking rows and executing the SPs...things I don't really know a whole lot about. The app uses ADODB.Command to execute the SP.
I have one VB6 exe (App.exe), running on the one server multiple times. This app calls a stored proc on the database which returns the next sequence number for that app. This sequence number field is unique for the instance of the application - there is 1 row in a table (tbl_SequenceNos) for each instance of the running application.
So for example, say we have running: App[a].exe and App[b].exe
tblSequenceNos looks like:
iAppNo| iNextSequenceNo
a | 1234
b | 4567
The stored procedure to get the next sequence number is relatively simple:
CREATE PROEDURE GetNextSequenceNo (#AppNo varchar(1), #NextSequenceNo int output)
AS
BEGIN
DECLARE #TempSequenceNo int
SELECT #NextSequenceNo = iNextSequenceNo
FROM tblSequenceNos
WHERE iAppNo = #AppNo
#NextSequenceNo = #NextSequenceNo + 1
UPDATE tblSequenceNos
SET iNextSequenceNo = #NextSequenceNo
WHERE iAppNo = #AppNo
END
When both App[a].exe and App[b].exe try to run this procedure to get their NextSequenceNo value, they are hanging for about 30Secs (ADO timeout?).
Because Each app never looks at the each others row, I thought that this would work concurrently without specifing an special Locking. Is there something I am missing? I thought perhaps I need to specify to lock the row only, not the whole table or Page? - I do not know what sql2008 does by default.
Any help is greatly appreciated!
Thank you in advance
Andrew
Your procedure is not thread safe and will produce incorrect results because between the select and the update multiple threads might get the same sequence nr.
CREATE PROCEDURE GetNextSequenceNo (#AppNo varchar(1), #NextSequenceNo int output)
AS
DECLARE #var table(seq int);
UPDATE tblSequenceNos
SET iNextSequenceNo = #NextSequenceNo + 1
OUTPUT inserted.iNextSequenceNo INTO #var;
WHERE iAppNo = #AppNo
select #NextSequenceNo = seq from #var
GO
Also make sure your iAppNo column is indexed. (This means an index on this column only or an index where this field is the first field in your index)
We're using SqlServer 2008. In SSMS, queries on the full text catalog might take 2-5 seconds the first time, but after that, return quite quickly.
On the other hand, running a query from via Linq2Sql will timeout.
Here's what we have:
The SQL Inline Table UDF
CREATE FUNCTION dbo.SearchArchiveFTS
(
#query nvarchar(255)
)
RETURNS #ret TABLE
(
ID NVarChar(12) NOT NULL,
snapshotDate DateTime NOT NULL,
-- about 10 more
)
AS BEGIN
declare #innerQuery nvarchar(255)
set #innerQuery = #query
insert into #ret
select ID,
snapshotDate,
-- about 10 more
from dbo.Archive a
where contains(a.*, #innerQuery)
return
Query in SSMS
select * from dbo.SearchArchiveFTS('query')
//3 seconds / 3k rows
Query in Linq2Sql
db.SearchArchiveFTS("query").ToArray();
// timeout exception
Any ideas on what the problem might be?
Check that your connection is not coming in with arithabort off. In SSMS it is ON
you can easily check like this
select arithabort,*
from sys.dm_exec_sessions
where is_user_process =1
just find the SPID that is hitting the DB
You also try to see what happens when you do this in SSMS
SET ARITHABORT OFF
select * from dbo.SearchArchiveFTS('query')
Does it now take a lot longer?
It is also possible that you are getting a bad plan from LINQ
You can clean out the procedure cache and memory buffers by running the following command
DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
Just be aware that it will wipe out all the plans on the server and SQL Server will have to recreate all of those and also read in all the data from disk again.......
I agree with #SQLMenace, when somehthing runs fast in SSMS but not from the application, it is usually a connection difference.
However, why use a function for something like that?
if you must use a function, why not use a table value function like this:
CREATE FUNCTION dbo.SearchArchiveFTS
(
#query nvarchar(255)
)
RETURNS TABLE
AS RETURN
(
select ID,
snapshotDate,
-- about 10 more
from dbo.Archive a
where contains(a.*, #query)
);
The issue appears to be related to a feature of SQL Server, where the FTS indices are unloaded after a period of inactivity. A background job to keep them fresh solved the problem.
Here's my configuration:
I have a re-runnable batch script that I use to update my database.
Inside of that batch script, I have code that says the following:
If Table 'A' doesn't exist, then create Table 'A' and insert rows into it.
Later on in that batch script, I create an schemabound indexed view on that table.
And if you didn't already know, indexed views require specific client settings.
Sometimes, when I re-run the script, that is after the table has been created, SQL Server Management Studio evaluates the "insert rows" code, which is protected by the 'If this table doesn't exist' code, and yields the following error:
Msg 1934, Level 16, State 1, Line 15
INSERT failed because the following SET options have incorrect settings: 'CONCAT_NULL_YIELDS_NULL, ANSI_WARNINGS, ANSI_PADDING, ARITHABORT'. Verify that SET options are correct for use with indexed views and/or indexes on computed columns and/or filtered indexes and/or query notifications and/or XML data type methods and/or spatial index operations.
Please note: If someone were to try this INSERT statement in a vacuum, I would fully expect SSMS to generate this error.
But not when it's protected by a conditional block.
My Question:
Does the SSMS compiler evaluate all expressions, regardless of whether they will actually be executed?
Yes, it evaluates all of them,take a look at this
declare #i int
select #i =1
if #i = 1
begin
declare #i2 int
set #i2 = 5
end
else
begin
declare #i2 int
set #i2 = 5
end
Msg 134, Level 15, State 1, Line 12
The variable name '#i2' has already been declared. Variable names must be unique within a query batch or stored procedure.
Another example with temp tables is here: What is deferred name resolution and why do you need to care?
your only way out would be to wrap it inside dynamic SQL
Note that most of the settings you mention are connection-level, i.e. in case you set/change them they stay in effect unless you close the connection or explicitly change their value.
Returning to your question. The error you mention looks like runtime error, i.e. the INSERT is actually being executed. It would be better if you could show your script (omitting details, but keeping batches).
Edit: it is not SSMS compiler that evaluates SQL you try to execute - it is SQL Server. What do you meant by 'evaluate'? Is it 'execute'? When you run a batch (which is what actually is being executed by a server), SQL Server first does syntactic analysis and throws error in case it finds any syntactic error, nothing is being executed at this point of time. In case syntax is ok, the server starts executing you batch.
Again, the error you show seems to be runtime - so I guess you'd carefully watch for the conditions and track what happens (or provide us more details about 'sometimes').
I need to use a native sql query in Hibernate with use of variable.
But hibernate throws an error saying: Space is not allowed after parameter prefix
So there is a conflict with the := mysql variable assignment and hibernate variable assignment.
Here is my sql query:
SET #rank:=0;
UPDATE Rank SET rank_Level=#rank:=#rank+1 ORDER BY Level;
the hibernate code (jpa syntax):
Query query = em.createNativeQuery(theQuery);
query.executeUpdate();
I can't use a stored procedure because my sql query is dynamically generated ('Level' can be 'int' or 'force'...)
How can I do this ?
thanks
Well, I finally use stored procedure (yes, what I don't want initially) to create dynamic query (I don't think it was possible).
Here is my code:
The stored procedure:
DELIMITER |
DROP PROCEDURE IF EXISTS UpdateRank |
CREATE PROCEDURE UpdateRank(IN shortcut varchar(30))
BEGIN
SET #rank=0;
SET #query=CONCAT('UPDATE Rank SET ', shortcut, '=#rank:=#rank+1 ORDER BY ', shortcut);
PREPARE q1 FROM #query;
EXECUTE q1;
DEALLOCATE PREPARE q1;
END;
|
DELIMITER ;
The tip is the use of the CONCAT function to dynamically create a query in the stored procedure.
Then, call the procedure in classic hibernate function:
Query q = em.createNativeQuery("CALL updateRank('lvl')");
q.executeUpdate();
I'll copy paste my answer from https://stackoverflow.com/a/25552002/3987202
Another solution for those of us who can't make the jump to Hibernate 4.1.3.
Simply use /*'*/:=/*'*/ inside the query. Hibernate code treats everything between ' as a string (ignores it). MySQL on the other hand will ignore everything inside a blockquote and will evaluate the whole expression to an assignement operator.
I know it's quick and dirty, but it get's the job done without stored procedures, interceptors etc.
Use MySQL Proxy to rewrite the query after Hibernate has sent the query to the database.
For example supply Hibernate with this,
UPDATE Rank SET rank_Level=incr(#rank) ORDER BY Level;
but rewrite it to this,
UPDATE Rank SET rank_Level=#rank:=#rank+1 ORDER BY Level;