I have a temp table used for intermediate calculation in a stored procedure.
Here is code segment:
CREATE TABLE #Updates
(
ID int not null,
ID2 int not null,
ID3 int not null
);
-- Do some operations and updates
IF OBJECT_ID('tempdb..#Updates','U') IS NOT NULL
DROP TABLE #Updates;
Since we are doing this a lot in a day. It causes SQL Server performance issue.
I want to change above code to
IF OBJECT_ID('tempdb..#Updates','U') IS NULL
BEGIN
CREATE TABLE #Updates
(
ID int not null,
ID2 int not null,
ID3 int not null
);
END
-- Do some operations and updates
IF OBJECT_ID('tempdb..#Updates','U') IS NOT NULL
DELETE FROM #Updates
I wonder if the new change will improve the SQL Server performance. If there is a better way to do this, please let me know, too.
Short version of answer
Remove the check for whether the temp table exists - these are only useful during development and manual execution of parts of the code
Unless you are deleting from the temp table then adding new data in, just let the temp table be removed naturally when the stored procedure finishes
Also consider whether a primary key and/or indexes will help
e.g., I've commented out stuff you don't need below and added a primary key on ID
-- IF OBJECT_ID('tempdb..#Updates','U') IS NULL
-- BEGIN
CREATE TABLE #Updates (
ID int not null PRIMARY KEY,
ID2 int not null,
ID3 int not null
);
-- END
<Do some operations and updates>
-- IF OBJECT_ID('tempdb..#Updates','U') IS NOT NULL
-- DELETE FROM #Updates
If, within that stored procedure, you
Create the temporary table
Insert values/data into it
Delete everything from it via DELETE FROM #Updates
Insert new values into it
then using TRUNCATE TABLE #Updates will be marginally faster that deleting from it.
Explanation/longer answer:
The temporary table is
only available during the current session/scope, and
deleted when the stored procedure finishes
If you run the stored procedure twice simultaneously, each will create, use, then delete its own temporary table - and they won't be able to be accessed by each other.
In terms of improving performance
If you are only using that table once (e.g., you create it, insert it, use it in a join, then are finished with it) you can instead move the SQL to be part of the join you are using (e.g., bypass the need to create a temp table). This avoids the cost of creating the temporary table, but may make your estimates in the new larger query worse, meaning poor performance
If you are using the table multiple times, you may consider putting indexes and/or a primary key on the temp table so it is sorted for those queries. Use columns that will be useful in joins with the other tables.
Temporary tables (e.g., in Temp_DB) are typically very fast. They also have some advantages over normal tables as they need much less transaction logging. I'd be surprised if the creation of a temporary table really affects time that much.
Pinal Dave does a very nice quick video about whether there is an effect of Dropping temporary tables in a stored procedure vs just letting them be removed automatically - in short the answer is 'no'.
UPDATE: I just did a test on an OK-ish computer that is about 10 years old now.
CREATE PROCEDURE _TestA AS BEGIN CREATE TABLE #a (a int); END;
GO
CREATE PROCEDURE _TestB AS BEGIN CREATE TABLE #a (a int); CREATE TABLE #b (a int); END;
GO
EXEC _TestA;
GO 1000
EXEC _TestB;
GO 1000
The first took 4 seconds, and the second took 6 seconds. This suggests that creating a temp table should only take a few milliseconds at most.
Related
I need to create a table, with many indexes that is scoped only to the running sproc.
I tried a table variable, but this doesn't seem to support indexes. A local temp table seems to create a 'real' table, and need to be explicitly dropped at the end of the proc, from which I'm inferring that it's also shared across concurrent runs and so would break.
What can I use to store data with indexes that is scoped only to the indicidual instance of the running sproc?
You don't need to worry about dropping the table. SQL Server does that automatically. As explained in the documentation:
A local temporary table created in a stored procedure is dropped automatically when the stored procedure is finished. The table can be
referenced by any nested stored procedures executed by the stored
procedure that created the table. The table cannot be referenced by
the process that called the stored procedure that created the table.
This is a result of the scoping rules for access to the temporary table.
I will admit, that in practice, I tend to explicitly drop temporary tables in stored procedures. The differences among:
create table temp
create table #temp
create table ##temp
are all too similar to rely on the fact that the second is dropped automatically, but the first and third are not. However, this is my "problem" and not a best practice.
Updated
The answer is don't worry at all since the temp table will be as if it was a local variable inside the stored procedure.
I wanted to make sure if the doubt I had was correct or not, so I made this test
create procedure TestTempData
as
begin
declare #date datetime = getdate()
if object_id('#testing') is not null
drop table #testing
create table #testing(
Id int identity(1,1),
[Date] datetime
)
print 'run at ' + format(#date,'HH:mm:ss')
insert into #testing([Date]) values
(dateadd(second,10,getdate())),
(dateadd(second,20,getdate())),
(dateadd(second,30,getdate()))
waitfor delay '00:00:15'
select * from #testing
end
then I ran this query
exec TestTempData
waitfor delay '00:00:02'
exec TestTempData
the result came as
run at 14:57:39
Id Date
1 2016-09-21 14:57:49.117
2 2016-09-21 14:57:59.117
3 2016-09-21 14:58:09.117
the second result
run at 14:57:56
Id Date
1 2016-09-21 14:58:06.113
2 2016-09-21 14:58:16.113
3 2016-09-21 14:58:26.113
If the concurrent runs will effect the #temp table, both results
should be the same which was not the case, It seems that the temp
table inside stored procedure acts like a local variable inside a
method.
Before chatting with Gordon Linoff
Since you mentioned that the temp table is shared across concurrent runs, your temp table should be unique for the current run.
Your stored procedure should look like this
create procedure YourProc(#userId int)
as
begin
if object_id('#temp' + #userId) IS NOT NULL
execute( 'DROP TABLE #temp' + #userId +'')
...
execute('insert into #temp' + #userId + 'values(...')
end
The above solution will ensure that no conflict will occur and no data will be lost since each execution will be unique per userId
you don't need to drop the table when you finish because it will be dropped automatically by it self
Hope this will help you
How can you implement the Singleton pattern in a SQL Server 2005/2008 stored procedure?
We want the stored procedure to return the next value from a table to a caller, and then update the value, so the next caller gets a different value ...
BUT there will be time when there are lots of callers!
AND we don't want blocking/time-out issues
PS. maybe singleton isn't the answer ... if not, how could you handle this?
By definition SINGLETON IS A LOCKING Pattern.
Talking about databases, there are so many DB professionals that get afraid when you mention the word "Lock", but locks per se are not a problem, they are a fundamental mechanism for the Relational Databases.
You must learn how locks works, what kind of locks exists, and treat them with respect.
Always work with short transactions, lock the minimum rows as you can, work with sets not individual rows.
Locks become a problem when they are massive, and when they last too much, and of course when you build a DEADLOCK.
So, the golden rule, when you must change data into a transaction, first put an exclusive Lock (UPDATE), never a Shared Lock (SELECT), it means sometimes you have to start doing a fake LOCK as in :
BEGIN TRAN
UPDATE table
set col1 = col1
Where Key = #Key
.......
COMMIT TRAN
Prior to SQL Server 2012, when I needed a serial I've done it in two ways:
Create an IDENTITY column, so after inserting you can get the value with the built in function SCOPE_IDENTITY() there is also ##IDENTITY, but if someone create a trigger that inserts into another table with an identity column starts the nightmare.
CREATE TABLE [table]
(
Id int IDENTITY(1,1) NOT NULL,
col2 ....
col3 ....
)
The second option is to add an serial column usually in the parent table or a table made for it plus a procedure (you can use client code) to get the serial:
--IF YOU CREATE A SERIAL HERE YOU'LL SPENT SOME SPACE,
--BUT IT WILL KEEP YOUR BLOCKINGS VERY LOW
CREATE TABLE Parent
(
Id,
ChildSerial int not null,
col2 ...
col3 ...
CONSTRAINT PK_Parent PRIMARY KEY (Id)
)
GO
--NAMED CONSTRAINT Auto names are random (avoid them)
ALTER TABLE Parent
ADD CONSTRAINT Parent_DF_ChildSerial DEFAULT(0) FOR ChildSerial;
GO
CREATE TABLE Child
(
Id int not null
col2..
colN..
--PLUS PRIMARY KEY... INDEXES, etc.
)
CREATE PROC GetChildId
(
#PatentId int
#ChildSerial int output --To use the proc from another proc
)
As
Begin
BEGIN TRAN
--YOU START WITH A LOCK, SO YOU'LL NEVER GET A DEADLOCK
--NOR A FAKE SERIAL (Two clients with the same number)
UPDATE Parent
SET ChildSerial = ChildSerial + 1
WHERE Id = #PatentId
If ##error != 0
Begin
SELECT #ChildSerial = -1
SELECT #ChildSerial
ROLLBACK TRAN
RETURN
End
SELECT #ChildSerial = ChildSerial
FROM Parent
WHERE Id = #PatentId
COMMIT TRAN
SELECT #ChildSerial --To Use the proc easily from a program
End
Go
Today I saw a nice post in which the author has proven that if you are updating a column of a table without any indexes defined, an "in place update" will occur and not traditional delete\insert.
Considering this I run a small test where I have created an Update trigger on table and try to access the INSERTED magic table and here is the catch.
I am able to access the INSERTED magic table, can someone explain me if in place update is not using traditional Delete\Insert? How come one can access the magic tables?
These are my SQL statement to prove this thing.
Main table :
CREATE TABLE TestingUpdate1 (
ID INT IDENTITY,
SomeString CHAR(50)
)
INSERT INTO TestingUpdate1 (SomeString)
VALUES
('One'),('Two'),('Three'),('Four'),('Five'),('Six'),('Seven'),('Eight'),('Nine')
CHECKPOINT -- truncate the log, DB is in simple recovery.
UPDATE TestingUpdate1
SET SomeString = 'NotFour'
WHERE ID = 4 -- one row
SELECT Operation, Context, AllocUnitName, [Transaction Name], Description FROM fn_dblog(NULL, NULL) AS TranLog
Second table :
CREATE TABLE TestingUpdate4 (
ID INT IDENTITY,
SomeString CHAR(50)
)
INSERT INTO TestingUpdate4 (SomeString)
VALUES
('One'),('Two'),('Three'),('Four'),('Five'),('Six'),('Seven'),('Eight'),('Nine')
Trigger :
CREATE TRIGGER ViewCustomerTrigger ON TestingUpdate1
INSTEAD OF UPDATE
AS
BEGIN
SET NOCOUNT ON
UPDATE TestingUpdate4
SET SomeString = i.SomeString
FROM INSERTED i
END
GO
select * from TestingUpdate4
select * from TestingUpdate1
Thanks in advance
The INSERTED and DELETED tables in an update trigger always show the logical before and after versions of the updated rows.
Whether that is physically implemented as an in place update or as an insert/delete is execution plan dependant and irrelevant to the contents of these tables.
what do Stored Procedures and Triggers in data base mean ?
how can i create Stored Procedures ?
how can i crest Triggers ?
if you have simple examples for each of these .please help :)
what i know is only about trigger which is activated if an action of(insert or delete or update ) violates the constrains specified but i don't know how to create ,so again if any have example please
Think of a Stored Procedure as a method in your code. It runs a specific set of instructions.
Stored Procedures are created to, for example, manage complex sets of data that would normally be a pain to handle along in your code.
You can create a Stored Procedure with the following instructions:
Oracle
CREATE OR REPLACE PROCEDURE P_PROCEDURE_NAME (
pParameter1 NUMBER
, pParameter2 VARCHAR2(100 Bytes)
) AS
BEGIN
-- Procedure code here...
END;
SQL Server
CREATE PROCEDURE cspProcedureName
#parameter1 int
, #parameter2 nvarchar(100)
AS
-- Procedure code here...
Oracle
As for the Triggers, they are sets of code called upon an action occuring to the related table. For instance, in Oracle, there are no INDENTITY columns such as SQL Server offers. Instead, Sequences are used along with Triggers to simulate the same. Hence, you will need to create an Oracle SEQUENCE, then the TRIGGER to update the ID field of your table.
CREATE SEQUENCE SEQ_CUSTOMERS
MINVALUE 1
MAXVALUE 65535
START WITH 1
INCREMENT BY 1;
CREATE OR REPLACE TRIGGER TRG_CUSTOMERS_INSERT
BEFORE INSERT
ON TBL_CUSTOMERS
FOR EACH ROW
BEGIN
:NEW.CUST_ID := SEQ_CUSTOMERS.NEXTVAL;
END;
SQL Server
A trigger example in SQL Server would be updating automatically the update datetime of a record. Consider the following:
CREATE TABLE Customers (
CustId int NOT NULL IDENTITY(1, 1) PRIMARY KEY
, CustName nvarchar(100) NOT NULL
, CreatedOn datetime DEFAULT GETDATE()
, LastUpdate datetime NOT NULL
)
GO
CREATE TRIGGER trgCustomersUpdt
AFTER UPDATE
ON Customers
AS
update Customers
set LastUpdate = GETDATE()
where CustId = inserted.Custid
GO
DISCLAIMER
This code has not been tested and may require minor changes for it to work properly against its respective RDBMS.
To sum it up, Triggers are mainly used to as illustrated here, despite there are many other possible use, such as building up an history of table changes that occured throught time, keeping all records of transactions into an history table or the like. The Stored Procedures are mainly used to perform complex database tasks where this would get too complex to do in code.
This is very similar to question 653714, but for MySQL instead of SQL Server.
Basically, I have a complicated select that is the basis for several stored procedures. I would like to share the code across the stored procedures, however, I'm not sure how to do this. One way I could do this is by making the shared select a stored procedure and then calling that stored procedure from the other ones. I can't figure out how to work with the result set of the nested stored procedure. If I could put them in a temp table I could use the results effectively, but I can't figure out how to get them in a temp table. For example, this does not work:
CREATE TEMPORARY TABLE tmp EXEC nested_sp();
The problem is, Stored Procedures don't really return output directly. They can execute select statements inside the script, but have no return value.
MySQL calls stored procedures via CALL StoredProcedureName(); And you cannot direct that output to anything, as they don't return anything (unlike a function).
MySQL Call Command
You cannot "SELECT INTO" with stored procedures.
Create the temporary table first and have your stored procedure to store the query result into the created temporary table using normal "INSERT INTO". The temporary table is visible as long as you drop it or until the connection is closed.
i know this is coming really late but since it took me ages to find a real solution i might as well share. I worked on an example that is below.
the tables created are:
CREATE TABLE BOOK(
B_ID INT NOT NULL AUTO_INCREMENT,
PRIMARY KEY(B_ID),
TITLE VARCHAR(100),
DESCRIPTION VARCHAR(30),
PRICE DOUBLE);
CREATE TABLE BOOK_COMMENT(
PRIMARY KEY(B_C_ID),
B_C_ID INT NOT NULL AUTO_INCREMENT,
REMARK VARCHAR(120),
B_ID INT,
FOREIGN KEY(B_ID) REFERENCES BOOK(B_ID));
CREATE TABLE AUTHOR(
A_ID INT NOT NULL AUTO_INCREMENT,
PRIMARY KEY(A_ID),
A_NAME CHAR(15),
B_ID INT,
FOREIGN KEY(B_ID) REFERENCES BOOK(B_ID));
DELIMITER
CREATE PROCEDURE BOOK_IMPORTANT( _PRICE DOUBLE, _B_ID INT, A_NAME CHAR(15), _BD_ID INT)
BEGIN
INSERT INTO BOOK(PRICE)
VALUES(_PRICE);
SET _B_ID=LAST_INSERT_ID();
INSERT INTO BOOK_COMMENT(B_ID)
VALUES(_B_ID);
SET _BD_ID=LAST_INSERT_ID();
INSERT INTO AUTHOR(A_NAME,B_ID)
VALUES(A_NAME,_BD_ID);
END
then use the following to insert the values.
CALL BOOK_IMPORTANT('0.79',LAST_INSERT_ID(),'',LAST_INSERT_ID());
LAST_INSERT_ID() takes the last auto increment of the table and inserts it into the referencing column of the child table.
In the procedure parameters _B_ID and _BD_ID represent the B_ID since I need B_ID as a foreign key in both tables.
Sorry for the excess wording. All the other guys expect you to automatically know how to do it. Hope it helps
My first reaction was "That sounds like a view to me". Doesn't that abstract it enough so you can just add the variability into an SP per case?
Anything that adds a temp table that wouldn't otherwise be there is a very likely antipattern.
Maybe it's a closed topic, but I would like to offer a solution based on the properties of MySQL temporary tables. First, the way to create the temporary table would not be to call the stored procedure "CREATE TEMPORARY TABLE tmp EXEC nested_sp ();". The query is to the temporary table of "infrastructure", (to name it somehow).
To achieve the desired result, it is necessary to create 2 stored procedures, the first stored procedure processes the data and fills the temporary "infrastructure" table, the second stored procedure, reads this table and continues with the process and finally "DROP" the "infrastructure" table
This is the first stored procedure:
CREATE DEFINER = 'root'#'localhost'
PROCEDURE cajareal.priv_test()
BEGIN
CREATE TEMPORARY TABLE IF NOT EXISTS tmp(
column1 TEXT
, column2 TEXT
, column3 TEXT
);
INSERT INTO tmp(column1, column2 , column3) VALUES(CURDATE(), CURRENT_DATE(), CURRENT_TIMESTAMP());
END
This is the second stored procedure:
CREATE DEFINER = 'root'#'localhost'
PROCEDURE cajareal.priv_caller()
BEGIN
CALL priv_test;
-- Read data of "infrastructure" table
SELECT * FROM tmp;
-- Do the business logic
-- Delete the "infrastructure" table
DROP TABLE tmp;
END
I use this technique to analyze a string and convert it to the table