Login or Sign Up to become a member!
LessThanDot Sit Logo

LessThanDot

Data Management

Less Than Dot is a community of passionate IT professionals and enthusiasts dedicated to sharing technical knowledge, experience, and assistance. Inside you will find reference materials, interesting technical discussions, and expert tips and commentary. Once you register for an account you will have immediate access to the forums and all past articles and commentaries.

LTD Social Sitings

Lessthandot twitter Lessthandot Linkedin Lessthandot friendfeed Lessthandot facebook Lessthandot rss

Note: Watch for social icons on posts by your favorite authors to follow their postings on these and other social sites.

Your profile

    Search

    XML Feeds

    Google Ads

    « Creating MongoDB as a service on Windows 8SHOW_STATISTICS Density showing key column - Why? »
    comments

    A customer's DBA team created a checklist for the development teams with some best practices for writing proper T-SQL and asked me to write some contributions for their tips document library. So if I do the research and write the documents I might as well post them here. The content may not be all sparkling and new but since there is a demand from customers, there are still people out there having trouble finding the correct information.
    So let's get started. The first document is why you should avoid SELECT * in your queries:

    For performance reasons

    To be honest this part of the post is based on Ted's post: SELECT * vs SELECT 1 with EXISTS.
    To check the performance impact I use a tool called SQLQueryStress to execute my queries and see how much time elapsed.
    To get started I need a table with a large number of columns, data is not necessary for this test so I use this script to generate a table with 127 columns:

    1. DECLARE @colnumber int = 1
    2. DECLARE @command VARCHAR(4000) =''
    3.  
    4. WHILE @colnumber <= 125
    5.     BEGIN
    6.         SET @command = @command + ' col' + CAST(@colnumber AS varchar(3)) + ' int, '
    7.         SET @colnumber += 1
    8.     END
    9. SET @command = 'CREATE TABLE StarPerform (PerfId int, ' + @command + ' Lastcolumn int)'
    10.  
    11. EXEC (@command)

    Now I query the table using the SQLQueryStress tool and I choose a high Number of Iterations to get a meaningful average:

    In the Client Seconds/Iteration (Avg) you see that the performance difference for an individual query is negligible but a similar query often executed on a busy server can result in 15 extra seconds on 5000 Iterations.

    Broken code

    Using SELECT * in Views is also a bad practice because changes to the underlying table will return unexpected results or fail completely.
    First I create a table and insert some data:

    1. --Create the table
    2. CREATE TABLE StarBreak
    3.  (
    4.     ID int IDENTITY (1,1),
    5.     Name varchar (10),
    6.     DateFirstPost date,
    7.     DateLastPost date
    8. );
    9. GO
    10.  
    11. --Insert some values
    12. INSERT INTO StarBreak (Name, DateFirstPost, DateLastPost)
    13.     VALUES ('Denis','20080207','20130101'),('Ted','20081107','20121231'),('Koen','20121123','20121227'),('Jes','20101210','20121221');
    14. GO

    Now I create and query a View to return all the columns:

    1. CREATE VIEW GetStarFromStarBreak
    2.     AS
    3.         SELECT * from Starbreak;
    4.        
    5. GO

    And I get this result back:

    Now let’s drop the table and recreate it but switch the position of the two datecolumns:

    1. --Drop the table
    2. DROP TABLE StarBreak;
    3. GO
    4.  
    5. --Create the table
    6. CREATE TABLE StarBreak
    7.  (
    8.     ID int IDENTITY (1,1),
    9.     Name varchar (10),
    10.     DateLastPost date,
    11.     DateFirstPost date
    12. );
    13. GO
    14.  
    15. --Insert some values
    16. INSERT INTO StarBreak (Name, DateFirstPost, DateLastPost)
    17.     VALUES ('Denis','20080207','20130101'),('Ted','20081107','20121231'),('Koen','20121123','20121227'),('Jes','20101210','20121221');
    18. GO

    When I query the table again I get the correct result:

    But when I query my view again I get the following result:

    You see that the column headers are in the same order as in the initial table but the data reflects the column order of the second table.
    Dropping the table, and adding a column in the middle will also result in the above behavior:

    1. --Drop the table
    2. DROP TABLE StarBreak;
    3. GO
    4.  
    5. --Create the table
    6. CREATE TABLE StarBreak
    7.  (
    8.     ID int IDENTITY (1,1),
    9.     Name varchar (10),
    10.     Gender char(1),
    11.     DateLastPost date,
    12.     DateFirstPost date
    13. );
    14. GO
    15.  
    16. --Insert some values
    17. INSERT INTO StarBreak (Name, DateFirstPost, DateLastPost)
    18.     VALUES ('Denis','20080207','20130101'),('Ted','20081107','20121231'),('Koen','20121123','20121227'),('Jes','20101210','20121221');
    19. GO

    What happens when I recreate the table but only 3 instead of 4 columns? Let’s try:

    1. --Drop the table
    2. DROP TABLE StarBreak;
    3. GO
    4.  
    5. --Create the table
    6. CREATE TABLE StarBreak
    7.  (
    8.     ID int IDENTITY (1,1),
    9.     Name varchar (10),
    10.     DateLastPost date,
    11. );
    12. GO
    13.  
    14. --Insert some values
    15. INSERT INTO StarBreak (Name, DateLastPost)
    16.     VALUES ('Denis','20130101'),('Ted','20121231'),('Koen','20121227'),('Jes','20121221');
    17. GO

    Now query the view again but use this query to make sure you only select the 3 existing columns:

    1. SELECT ID, Name, DateLastPost FROM GetStarFromStarBreak

    And the result is:

    You see the code breaks because the view still expects 4 columns although you specified you only query 3 columns from the view.

    Conclusion

    We have seen several reasons to stay away from the SELECT * statement but we do understand the pain in typing in 127 column names. So here is a last tip:
    When you drag the Columns folder of your table in Object Explorer to the Query Pane, SQL Server Management Studio will automatically list the column names separated with commas for you.

    About the Author

    User bio imageAxel started his IT career more than a decade ago. After a few months he was the accidental DBA for the SQL Server 6.5 running the Service Desk application. It didn't took long or Axel started to focus on SQL Server and after another year he became the full-time DBA in a large Belgian datacenter managing the SQL Servers for the hosted customers.It's more than five years now since he switched to consulting and teaching SQL Server. Axel is a Microsoft Certified DBA and Trainer.
    Social SitingsTwitterLinkedInLTD RSS Feed
    2668 views
    InstapaperVote on HN

    3 comments

    Comment from: Timothy Batts [Visitor] · http://www.sqlbattsman.com
    Timothy Batts Great post. I was not aware of the issues with view definitions actually returning incorrect data. Only that new columns would not appear in the view without refreshing the view definition.

    Another reason not to use SELECT * is maintainability. There is no way to know the requirements of the application and whether it actually needs all the columns when maintaining code later on, not without a considerable amount of additional research and effort. Not to mention, if you plan to drop an unused column you can't simply search the code base to make sure it is not being referenced anywhere.
    01/02/13 @ 07:17
    Comment from: Ted Krueger (onpnt) [Member]
    Ted Krueger (onpnt) Nice post! I had a company I worked for lose a lot of money because of the view issue returning incorrect calculations. Here is another post on it and preventing it if you do find yourself in a select * and view situation (maintain the meta data type deal)
    http://blogs.lessthandot.com/index.php/DataMgmt/DBAdmin/sql-server-views-and-meta
    01/02/13 @ 14:18
    Comment from: Axel Achten (axel8s) [Member]
    Axel Achten (axel8s) Thanks for the comments and tips
    01/03/13 @ 01:20

    Leave a comment


    Your email address will not be revealed on this site.

    To mislead the spambots.

    Your URL will be displayed.
    (Line breaks become <br />)
    (Name, email & website)
    (Allow users to contact you through a message form (your email will not be revealed.)