Showing posts with label SQL Series. Show all posts
Showing posts with label SQL Series. Show all posts
Thursday, November 17, 2016
What's new in SQL Server 2016: CREATE OR ALTER
SQL Server 2016 Service Pack 1 added the CREATE OR REPLACE functionality, however in SQL Server, it is called CREATE OR ALTER. Finally it is here, this has been asked for since the 90s, it was on the SQL Server wishlist (who remembers that before they had connect :-)
CREATE OR ALTER can be used with the following four object types
STORED PROCEDURES
FUNCTIONS
TRIGGERS
VIEWS
Let's take a look how this all works
If you want to run this code, you need to be on SQL Server 2016 Service pack 1 or higher or on vNext, the @@VERSION function on SP1 and vNext returns the following
Microsoft SQL Server 2016 (SP1) (KB3182545) - 13.0.4001.0 (X64) Oct 28 2016 18:17:30
Microsoft SQL Server vNext (CTP1) - 14.0.1.246 (X64) Nov 1 2016 23:24:39
Before they added CREATE OR ALTER, you had a couple of options to create rerunable scripts. The first way was dropping the proc if it existed and having the CREATE PROC in the same script, it looked like this
--old way of dropping a proc then having a create script IF OBJECT_ID('procTest') is not null DROP PROCEDURE procTest GO CREATE PROCEDURE procTest AS BEGIN PRINT (1) END; GO
Another way would be to create a dummy proc if the proc didn't exist already and then just have the ALTER PROC part in your script
--another way is to have a dummy proc created, --that way your alter part is always the same IF OBJECT_ID('dbo.procTest') IS NULL EXEC ('CREATE PROCEDURE dbo.procTest AS RETURN 0;') GO ALTER PROCEDURE procTest AS BEGIN PRINT (1) END; GO
In SQL Server 2016 with Service Pack 1, this becomes so much easier. Here is what it looks like
-- the easier way in sql server 2016 SP1 and up CREATE OR ALTER PROCEDURE procTest AS BEGIN PRINT (1) END; GO
Here is how that looks with a function, pretty much the same as a procedure
-- works the same with functions CREATE OR ALTER FUNCTION fnTest() RETURNS INT AS BEGIN RETURN(1) END; GO
The view looks like this
-- also works with views CREATE OR ALTER VIEW vwTest AS SELECT 1 AS col; GO
With triggers it is pretty much the same, here is the code that you can run, I first created a table otherwise I would not be able to create a trigger
-- first we need a table for the trigger IF NOT EXISTS(SELECT * FROM sys.tables WHERE name = 'BooFar') CREATE TABLE BooFar(id int) GO -- works with triggers CREATE OR ALTER TRIGGER trTest ON BooFar AFTER INSERT, UPDATE AS RAISERROR ('Hello from trigger', 1, 10); GO -- just a test to make sure the trigger works INSERT BooFar values(1) -- you should see this in the message tab /* Hello from trigger Msg 50000, Level 1, State 10 (1 row(s) affected) */
The CREATE OR REPLACE syntax does NOT work with DDL triggers. If you execute this the first time it will run fine.
CREATE OR ALTER TRIGGER safety ON DATABASE FOR DROP_TABLE, ALTER_TABLE AS PRINT 'You must disable Trigger "safety" to drop or alter tables!' ROLLBACK;
Now run it again, you will get this error
Msg 2714, Level 16, State 2, Procedure safety, Line 1 [Batch Start Line 77]
There is already an object named 'safety' in the database.
I submitted a connect item for this: https://connect.microsoft.com/SQLServer/feedback/details/3111866
I want them to either disable CREATE OR ALTER for DDL triggers or they should fix it so it doesn't error on a second run
Tor wrap this up, let's drop all these objects we just created, we will do that by using the Drop if exists syntax
-- drop everything by using -- DROP object IF EXISTS DROP TABLE IF EXISTS BooFar DROP PROCEDURE IF EXISTS procTest DROP VIEW IF EXISTS vwTest
You can find the github repo for the series here whatisnewinsqlserver2016, all the code for this post can be found here CREATE Or ALTER
Saturday, November 12, 2016
What's new in SQL Server 2016: Truncate partitions
In my The best thing about the PASS summit for me is... post I said that I would do the following
I will also do a series about new stuff in SQL Server 2016, but that will be in between all the other posts. Whenever someone asked during a session how many people were already on SQL Server 2016, very few hands went up, this is the reason, I want to blog about this as well.This is the first post in that series
For all these series of posts, I plan to have a repo on github with a yet to be determined name. Then I will have all the SQL code for all the series organized there
You can find the github repo for the series here whatisnewinsqlserver2016, all the code for this post can be found here TruncatePartitions
New in SQL Server is the ability to truncate a partition or more than 1 partition, this is very nice because we all know that truncate is much faster than a delete. Let's see how this all works
First create this simple table
CREATE TABLE SalesPartitioned( YearCol SMALLINT NOT NULL, OrderID INT NOT NULL, SomeData UNIQUEIDENTIFIER DEFAULT newsequentialid()) GO
Now it is time to insert some data, we are going to create data for 6 years, we will use those years then to partition the data on. This query will insert 6 times 2048 rows, 2048 rows per year
INSERT SalesPartitioned (YearCol,OrderID) SELECT 2013,number FROM master..spt_values WHERE type = 'P' UNION ALL SELECT 2014,number + 2048 FROM master..spt_values WHERE type = 'P' UNION ALL SELECT 2015,number + 4096 FROM master..spt_values WHERE type = 'P' UNION ALL SELECT 2016,number + 6144 FROM master..spt_values WHERE type = 'P' UNION ALL SELECT 2017,number + 8192 FROM master..spt_values WHERE type = 'P' UNION ALL SELECT 2018,number + 10240 FROM master..spt_values WHERE type = 'P'
Now let's create the partition function
CREATE PARTITION FUNCTION pfFiscalYear(SMALLINT) AS RANGE LEFT FOR VALUES(2013,2014,2015,2016,2017) GO
Create the partition scheme
CREATE PARTITION SCHEME psFiscalYear AS PARTITION pfFiscalYear ALL TO ([PRIMARY]) GO
Add a primary key to the table, add it to the partition scheme we created above
ALTER TABLE dbo.SalesPartitioned ADD CONSTRAINT PK_Sales PRIMARY KEY CLUSTERED (YearCol,OrderID) ON psFiscalYear(YearCol) GO
Now let's see what we have as far as counts for each partition
SELECT partition_number,rows FROM sys.partitions WHERE object_id = OBJECT_ID('SalesPartitioned')
Here are the results
partition_numberrows
12048
22048
32048
42048
52048
62048
As you can see we have 6 partitions, each partition has 2048 rows
We can verify this by running a count ourselves
SELECT YearCol, $PARTITION.pfFiscalYear(YearCol) AS Partition, COUNT(*) AS [COUNT] FROM SalesPartitioned GROUP BY $PARTITION.pfFiscalYear(YearCol),YearCol ORDER BY Partition; GO
YearColPartitionCOUNT
201312048
201422048
201532048
201642048
201752048
201862048
Now it is time to truncate a partition.
In order to truncate a partition, you use the following syntax
TRUNCATE TABLE ........
WITH ( PARTITIONS ( { <partition_number_expression> | <range> } [ , ...n ] ) )
So if we just want to truncate partition 2, we would execute the following
TRUNCATE TABLE SalesPartitioned WITH (PARTITIONS (2)); GO
Checking those same count queries from before shows that partition 2 has no rows after we executed the truncate command
SELECT partition_number,rows FROM sys.partitions WHERE object_id = OBJECT_ID('SalesPartitioned')
partition_numberrows
12048
20
32048
42048
52048
62048
SELECT YearCol, $PARTITION.pfFiscalYear(YearCol) AS Partition, COUNT(*) AS [COUNT] FROM SalesPartitioned GROUP BY $PARTITION.pfFiscalYear(YearCol),YearCol ORDER BY Partition; GO
YearColPartitionCOUNT
201312048
201532048
201642048
201752048
201862048
There are two ways you can truncate a bunch of partitions, for example if you want to remove 4,5 and 6, you can use WITH (PARTITIONS (4, 5, 6)) or you can use a range like shown in the code below
TRUNCATE TABLE SalesPartitioned WITH (PARTITIONS (4 TO 6)); GO
After we execute that and we check the counts again, we see that we are now only left with partitions 1 and 3
SELECT partition_number,rows FROM sys.partitions WHERE object_id = OBJECT_ID('SalesPartitioned')
Here are the results from that query
partition_numberrows
12048
20
32048
40
50
60
SELECT YearCol, $PARTITION.pfFiscalYear(YearCol) AS Partition, COUNT(*) AS [COUNT] FROM SalesPartitioned GROUP BY $PARTITION.pfFiscalYear(YearCol),YearCol ORDER BY Partition; GO
Here are the results
YearColPartitionCOUNT
201312048
20153 2048
What happens if you specify an invalid partition in your truncate statement?
TRUNCATE TABLE SalesPartitioned WITH (PARTITIONS (12));
You get the following message
Msg 7722, Level 16, State 2, Line 1
Invalid partition number 12 specified for table 'SalesPartitioned', partition number can range from 1 to 6.
There you have it, this is how truncate partitions work
You can find the github repo for the series here whatisnewinsqlserver2016, all the code for this post can be found here TruncatePartitions
Subscribe to:
Posts (Atom)