SQL Server TSQL Coding Conventions, Best Practices, and Programming Guidelines

  • Do not prefix your stored procedure names with “sp_”. The prefix sp_ is reserved for system stored procedure that ship with SQL Server. Whenever SQL Server encounters a procedure name starting with sp_, it first tries to locate the procedure in the master database, then it looks for any qualifiers (database, owner) provided, then it tries dbo as the owner. So you can really save time in locating the stored procedure by avoiding the “sp_” prefix.

  • Views are generally used to show specific data to specific users based on their interest. Views are also used to restrict access to the base tables by granting permission only on views. Yet another significant use of views is that they simplify your queries. Incorporate your frequently required, complicated joins and calculations into a view so that you don’t have to repeat those joins/calculations in all your queries. Instead, just select from the view.

  • Use User Defined Datatypes if a particular column repeats in a lot of your tables, so that the datatype of that column is consistent across all your tables.

  • Do not let your front-end applications query/manipulate the data directly using SELECT or INSERT/UPDATE/DELETE statements. Instead, create stored procedures, and let your applications access these stored procedures. This keeps the data access clean and consistent across all the modules of your application, and at the same time centralizing the business logic within the database.

  • Try not to use TEXT or NTEXT datatypes for storing large textual data. The TEXT datatype has some inherent problems associated with it. For example, you cannot directly write or update text data using the INSERT or UPDATE statements. Instead,  you have to use special statements like READTEXT, WRITETEXT and UPDATETEXT. There are also a lot of bugs associated with replicating tables containing text columns. So, if you don’t have to store more than 8KB of text, use CHAR(8000) or VARCHAR(8000) datatypes instead.

  • If you have a choice, do not store binary or image files (Binary Large Objects or BLOBs) inside the database. Instead, store the path to the binary or image file in the database and use that as a pointer to the actual binary file stored elsewhere on a server. Retrieving and manipulating these large binary files is better performed outside the database, and after all, a database is not meant for storing files.

  • Use the CHAR data type for a column only when the column is non-nullable. If a CHAR column is nullable, it is treated as a fixed length column in SQL Server 7.0+. So, a CHAR(100), when NULL, will eat up 100 bytes, resulting in space wastage. So, use VARCHAR(100) in this situation. Of course, variable length columns do have a very little processing overhead over fixed length columns. Carefully choose between CHAR and VARCHAR depending up on the length of the data you are going to store.

  • Avoid dynamic SQL statements as much as possible. Dynamic SQL tends to be slower than static SQL, as SQL Server must generate an execution plan every time at runtime. IF and CASE statements come in handy to avoid dynamic SQL. Another major disadvantage of using dynamic SQL is that it requires users to have direct access permissions on all accessed objects, like tables and views. Generally, users are given access to the stored procedures which reference the tables, but not directly on the tables. In this case, dynamic SQL will not work. Consider the following scenario where a user named ‘dSQLuser’ is added to the pubs database and is granted access to a procedure named ‘dSQLproc’, but not on any other tables in the pubs database. The procedure dSQLproc executes a direct SELECT on titles table and that works. The second statement runs the same SELECT on titles table, using dynamic SQL and it fails with the following error:

    Server: Msg 229, Level 14, State 5, Line 1
    SELECT permission denied on object ‘titles’, database ‘pubs’, owner ‘dbo’.

    To reproduce the above problem, use the following commands:

    sp_addlogin ‘dSQLuser’
    GO
    sp_defaultdb ‘dSQLuser’, ‘pubs’
    USE pubs
    GO
    sp_adduser ‘dSQLUser’, ‘dSQLUser’
    GO
    CREATE PROC dSQLProc
    AS
    BEGIN
    SELECT * FROM titles WHERE title_id = ‘BU1032’ –This works
    DECLARE @str CHAR(100)
    SET @str = ‘SELECT * FROM titles WHERE title_id = ”BU1032”’
    EXEC (@str) –This fails
    END
    GO
    GRANT EXEC ON dSQLProc TO dSQLuser
    GO

    Now login to the pubs database using the login dSQLuser and execute the procedure dSQLproc to see the problem.

  • Consider the following drawbacks before using the IDENTITY property for generating primary keys. IDENTITY is very much SQL Server specific, and you will have problems porting your database application to some other RDBMS. IDENTITY columns have other inherent problems. For example, IDENTITY columns can run out of numbers at some point, depending on the data type selected; numbers can’t be reused automatically, after deleting rows; and replication and IDENTITY columns don’t always get along well.
  • So, come up with an algorithm to generate a primary key in the front-end or from within the inserting stored procedure. There still could be issues with generating your own primary keys too, like concurrency while generating the key, or running out of values. So, consider both options and go with the one that suits you best.

    • Minimize the use of NULLs, as they often confuse the front-end applications, unless the applications are coded intelligently to eliminate NULLs or convert the NULLs into some other form. Any expression that deals with NULL results in a NULL output. ISNULL and COALESCE functions are helpful in dealing with NULL values. Here’s an example that explains the problem:

      Consider the following table, Customers which stores the names of the customers and the middle name can be NULL.

      CREATE TABLE Customers
      (
      FirstName varchar(20),
      MiddleName varchar(20),
      LastName varchar(20)
      )

      Now insert a customer into the table whose name is Tony Blair, without a middle name:

      INSERT INTO Customers 
      (FirstName, MiddleName, LastName) 
      VALUES (‘Tony’,NULL,’Blair’)

      The following SELECT statement returns NULL, instead of the customer name:

      SELECT FirstName + ‘ ‘ + MiddleName + ‘ ‘ + LastName FROM Customers

      To avoid this problem, use ISNULL as shown below:

      SELECT FirstName + ‘ ‘ + ISNULL(MiddleName + ‘ ‘,”) + LastName FROM Customers

    • Use Unicode datatypes, like NCHAR, NVARCHAR, or NTEXT, if your database is going to store not just plain English characters, but a variety of characters used all over the world. Use these datatypes only when they are absolutely needed as they use twice as much space as non-Unicode datatypes.
      Continues…

    Leave a comment

    Your email address will not be published.