Pages

Showing posts with label TSQL. Show all posts
Showing posts with label TSQL. Show all posts

Monday, June 30, 2014

Difference Between COALESCE and ISNULL

ISNULL is a T-SQL function to replace NULL values as COALESCE does. At some cases these two functions get the same results but there are some differences. Below is a summary of their differences and I hope that it will help you decide which function to use when you need to determine the one with better performance or better concurrency control.


COALESCE ISNULL
Standard ANSI SQL? Yes No (Only for T-SQL)
Numbers of Parameters Two or more parameters. Two parameters only.
Data type determination of the resulting expression Determined by the data type of parameters with the highest precedence Determined by data type of the first parameter
Allow both inputs to be untyped NULLs?
No. For SELECT COALESCE(NULL, NULL); , it will return an error. You need to have at least one of the null values be a typed NULL. 

SELECT COALESCE(CAST(NULL AS INT), NULL);

Yes. For SELECT ISNULL(NULL, NULL); it will return a NULL typed as an integer.
NULLability of the resulting expression Considered to be NULL with non-null parameters. Always considered NOT NULLable
Working with subquery as input parameters When executing COALESCE((subquery), 1), the subquery is evaluated twice.  you can get different results depending on the isolation level of the query. Evaluated only once.

Friday, May 30, 2014

How to: Extract only Date Part From DateTime

It is common practice to extract only date part from datetime format, such as for a datetime of 2014-05-30 15:31:58.860, only 2014-05-30 is returned. Today we will show three main methods to choose from.

Method 1:

SELECT convert(DATE, GETDATE() )

Method 2:


SELECT CONVERT(VARCHAR(10),GETDATE(),126)

Method 3:


SELECT DATEADD(D, 0, DATEDIFF(D, 0, GETDATE()))

will mask the time part as 00:00:00.000.  It sometimes is regarded as better performance here.

Tuesday, November 19, 2013

Is Truncate DDL or DML?

Recently as I referred to the book of Microsoft SQL Server 2012 T-SQL Fundamentals by Ben-Gan, Itzik for DML definitions, there is a conclusion about TRUNCATE statement that surprised me at first:
"Another common misunderstanding is that TRUNCATE is a DDL statement, but in fact it is a DML statement."
Yes. I had always had that “misunderstanding” to regard TRUNCATE as DDL because TRUNCATE statement removes the data by deallocating pages used to store the table and records only the page deallocations in the transaction log. It is not simply row removal as DELETE statement.

After further discussion with the author (I really appreciated that Itzik spent time to help me understand his conclusion.), it turned out TRUNCATE is listed under Data Manipulation Language (DML) in the standard document ISO_9075_02_Foundation_2011_E. Also, the Standard ISO/ANSI SQL deals with only the logical aspects of the code, and logically TRUNCATE statement deletes all rows from a table.

At the same time, Microsoft listed TRUNCATE TABLE as Data Definition Language (DDL) Statements together with ALTER, CREATE, DISABLE/ENABLE TRIGGER, DROP, and UPDATE STATISTICS.

Isn’t it interesting to know about that?

Wednesday, November 13, 2013

How to: Set Row Versioning-based Transaction Isolation Levels


Row versioning-based transaction isolation levels were introduced since SQL Server 2005. They use row versioning for concurrency controls instead of locks. Therefore they are very attractive because no more blocking issues with usage of row versioning. However, since row versioning-based isolation levels are related to both database-level settings and transaction-level settings, it is very easy to get confused about how to set it right. I hope you will get a clear idea after reading this.


Two types, three commands?


There are two types of transaction isolation levels based on row versioning. One is READ COMMITTED using row versioning. (It is also known as READ COMMITTED SNAPSHOT isolation or RCSI. ) The other is SNAPSHOT isolation. The difference between the two is the "cutoff" time for the latest row versions they will use.  RCSI uses latest row versions when the statement starts while SNAPSHOT uses the latest committed row when the transaction starts.
On the other hand, there are three commands involved in order to set RCSI and SNAPSHOT isolation levels:
  1. ALTER DATABASE <current_database> SET READ_COMMITTED_SNAPSHOT ON;
  2. ALTER DATABASE <current_database>  SET ALLOW_SNAPSHOT_ISOLATION ON;
  3. SET TRANSACTION ISOLATION LEVEL SNAPSHOT
The first two commands are database-level settings and can be turned on at the same time. So the question is:

 

What is the right combination?


First of all, let us do some experiments. Create a table with two rows:

create table tranTest (id int primary key, price int)
insert tranTest values (1, 10), (2, 20) 

Suppose both ALLOW_SNAPSHOT_ISOLATION and READ_COMMITTED_SNAPSHOT are set OFF. You can double check the isolation levels by following the steps in How to Check Transaction Isolation Levels.

Experiment 1: ALLOW_SNAPSHOT_ISOLATION is OFF with READ_COMMITTED_SNAPSHOT is ON;

Run the following code in session 1:
ALTER DATABASE DemoSQL2012 SET ALLOW_SNAPSHOT_ISOLATION ON;
Next, run the following code in session 2:
SET TRANSACTION ISOLATION LEVEL SNAPSHOT

Ok, it seems fine with no error message appears. 
However, when you begin a new transaction in the same session that you have tried setting SNAPSHOT isolation, it will give the following error:


Msg 3952, Level 16, State 1, Line 3
Snapshot isolation transaction failed accessing database 'xxx' because snapshot isolation is not allowed in this database. Use ALTER DATABASE to allow snapshot isolation.

 

That means that in order to start a SNAPSHOT transaction, you must have ALLOW_SNAPSHOT_ISOLATION to be turned on. Only when ALLOW_SNAPSHOT_ISOLATION database option is set ON, the support for snapshot isolation transaction is activated. Moreover, the database engine does not generate row versions for modified data until all active transactions that have data modified complete. Interestingly, it does not matter whether READ_COMMITTED_SNAPSHOT is ON or OFF.
After you set ALLOW_SNAPSHOT_ISOLATION option on, run the following codes:

---- EXPERIMENT for SNAPSHOT ISOLATION
-- Connection 1
BEGIN TRAN;

  SELECT id, price
  FROM dbo.tranTest
  WHERE id = 2;
  UPDATE dbo.tranTest
    SET price += 1.00
  WHERE id = 2;

  SELECT id, price
  FROM dbo.tranTest
  WHERE id = 2;

-- Connection 2
SET TRANSACTION ISOLATION LEVEL SNAPSHOT;

BEGIN TRAN;

  SELECT id, price
  FROM dbo.tranTest
  WHERE id = 2;
-- 20
-- Connection 1
COMMIT TRAN;

-- Connection 2
  SELECT id, price
  FROM dbo.tranTest
  WHERE id = 2;
--- 20
COMMIT TRAN;

BEGIN TRAN;

  SELECT id, price
  FROM dbo.tranTest
  WHERE id = 2;
--- 21
COMMIT TRAN;

-- Connection 1
-- Cleanup
UPDATE dbo.tranTest
  SET price = 20.00
WHERE id = 2;


Notice that in session 2, we got same results for reading in the first transaction but a different result for the later transaction. That proves that SNAPSHOT isolation level always read the last committed row version when the transaction starts. The cutoff for the row to be read is when transaction starts.


Experiment 2: ALLOW_SNAPSHOT_ISOLATION is ON with READ_COMMITTED_SNAPSHOT is ON;


In order to enable the database option for READ_COMMITTED_SNAPSHOT, please only have one active session connected to the related database. Then run the command:

ALTER DATABASE DemoSQL2012 SET READ_COMMITTED_SNAPSHOT ON;


Then test the isolation level by running these codes:
--- EXPERIMENT FOR READ_COMMITTED_SNAPSHOT
-- Connection 1
BEGIN TRAN;

  SELECT id, price
  FROM dbo.tranTest
  WHERE id = 2;

  UPDATE dbo.tranTest
    SET price += 1.00
  WHERE id = 2;

  SELECT id, price
  FROM dbo.tranTest
  WHERE id = 2;

-- Connection 2
BEGIN TRAN;

  SELECT id, price
  FROM dbo.tranTest
  WHERE id = 2;
-- 20
-- Connection 1
COMMIT TRAN;

-- Connection 2
  SELECT id, price
  FROM dbo.tranTest
  WHERE id = 2;
--- 21
COMMIT TRAN;

-- Connection 1
-- Cleanup
UPDATE dbo.tranTest
  SET price = 20.00
WHERE id = 2;


If you get the same results in session 2 as shown above, congratulations! The difference in the results demonstrates that READ_COMMITTED_SNAPSHOT always get the last committed row version right before the statement starts.

Conclusion


In order set SNAPSHOT transaction isolation, you need to first turn on the ALLOW_SNAPSHOT_ISOLATION option at database level. Then at the related session, run "SET TRANSACTION ISOLATION LEVEL SNAPSHOT" to set isolation levels at transaction level.

On the other hand, for RCSI, you only need to have READ_COMMITTED_SNAPSHOT turned on at database level.