Important alert: (current site time 7/15/2013 7:39:07 PM EDT)
 

article

Getting a row cound without doing a table scan.

Email
Submitted on: 4/21/2003 10:18:46 AM
By: Andrew Novick  
Level: Intermediate
User Rating: By 3 Users
Compatibility: SQL Server 2000
Views: 9902
author picture
(About the author)
 
     Tells you how to go about getting a row count without doing a table scan. It explains some of the columsn of the sysindexes system table that are the source of the information and provides the code you need to obtain it easily.

 
 
Terms of Agreement:   
By using this article, you agree to the following terms...   
  1. You may use this article in your own programs (and may compile it into a program and distribute it in compiled format for languages that allow it) freely and with no charge.
  2. You MAY NOT redistribute this article (for example to a web site) without written permission from the original author. Failure to do so is a violation of copyright laws.   
  3. You may link to this article from another website, but ONLY if it is not wrapped in a frame. 
  4. You will abide by any additional copyright restrictions which the author may have placed in the article or article's description.
				Brought to you by Novick Software http://www.NovickSoftware.com/

Visit http://www.NovickSoftware.com for additional material about SQL Server, Visual Basic, ASP, XML, and security.

Visit the T-SQL UDF of the Week at: http://www.NovickSoftware.com/UdfOfWeek/UDFofWeek.htm

Check out the UDF Frequently Asked Questions at: http://www.novicksoftware.com/UdfOfWeek/UDF_FAQ.htm

To ask a UDF related question or to contribute a UDF, send e-mail to udf@NovickSoftware.com

Sign up for this newsletter at:
http://www.novicksoftware.com/UdfOfWeek/UDFofWeekSignup.htm


If you don't require an exact answer, it isn't necessary use a SELECT count(*) query on the rows in a table to get the row count. SQL Server keeps the row count in sysindexes and it can be retrieved there. The key is to select the correct record from sysindexes.
Sysindexes is a system table that exists in every database. SQL Server maintains at least one row in sysindexes for every user table. A few of the most important columns are:
Column   Data Type  Description
-------- ---------- --------------------
id       int        ID of the table referred to by this row
indid    int        See the text that follows.
rowcnt   bigint     Number of rows in the index

The indid column tells us what part of the table structure this row of sysindexes is referring to:
indid Description
-------- -------------------------------
0        Table data when there is no clustered index
1        Referes to the clustered index
2 - 254  Non-clustered indexes
255      Text or Image data pages

A table will only have an entry in sysindexes with an indid value of for 0 or 1, never both. That's the entry that we're interested in because its rowcnt field gives is the number of rows in the table. There's a query that shows the table, index and indid from the pubs database:

USE pubs
GO
SELECT so.[name] as [table name]
      , CASE WHEN si.indid between 1 and 254
           THEN si.[name] ELSE NULL END 
           AS [Index Name]
      , si.indid 
    FROM sysindexes si
        INNER JOIN sysobjects so
            ON si.id = so.id
    WHERE si.indid < 2 
        AND so.type = 'U' -- Only User Tables
         AND so.[name] != 'dtproperties'
    ORDER BY so.[name]

(Results) table name Index Name indid -------------- ------------------ ------ authors UPKCL_auidind 1 discounts NULL 0 employee employee_ind 1 jobs PK__jobs__117F9D94 1 pub_info UPKCL_pubinfo 1 publishers UPKCL_pubind 1 roysched NULL 0 sales UPKCL_sales 1 stores UPK_storeid 1 titleauthor UPKCL_taind 1 titles UPKCL_titleidind 1

As you can see from the results, most of the indexes are clustered (indid=1) but a few tables such as discounts don't have a clustered index they have a heap (indid=0).

I started this newsletter with "If you don't need an exact answer..." That's because there are times when rowcnt is not the exact number of records in the table. This can be corrected by updating statistics on the table with:

dbcc updateusage<
go

Here's the CREATE FUNCTION script for udf_Tbl_RowCOUNT:

CREATE FUNCTION dbo.udf_Tbl_RowCOUNT (
 @sTableName sysname -- Table to retrieve Row Count
) RETURNS INT -- Row count of the table, NULL if not found.
/*
* Returns the row count for a table by examining sysindexes.
* This function must be run in the same database as the table.
*
* Example:
SELECT dbo.udf_Tbl_RowCOUNT ('')
* Test
 PRINT 'Test 1 Bad table ' + CASE WHEN SELECT 
        dbo.udf_Tbl_RowCOUNT ('foobar') is NULL
         THEN 'Worked' ELSE 'Error' END
 
* © Copyright 2002 Andrew Novick http://www.NovickSoftware.com
* You may use this function in any of your SQL Server databases
* including databases that you sell, so long as they contain 
* other unrelated database objects. You may not publish this 
* UDF either in print or electronically.
***************************************************************/
AS BEGIN
 
 DECLARE @nRowCount INT -- the rows
 DECLARE @nObjectID int -- Object ID
 SET @nObjectID = OBJECT_ID(@sTableName)

-- Object might not be found IF @nObjectID is null RETURN NULL SELECT TOP 1 @nRowCount = rows FROM sysindexes WHERE id = @nObjectID AND indid < 2 RETURN @nRowCount END GO GRANT EXECUTE ON [dbo].[udf_Tbl_RowCOUNT] TO PUBLIC GO


Let's use it:

use pubs -- assuming the UDF was created in pubs
go
SELECT [name]
       , dbo.udf_Tbl_RowCOUNT ([name]) as [Row Count]
    FROM sysobjects
    WHERE type='U' and name != 'dtproperties'
    ORDER BY [name]
GO

(Results) name Row Count ------------ --------- authors 24 discounts 3 employee 43 jobs 14 pub_info 8 publishers 8 roysched 86 sales 21 stores 6 titleauthor 25 titles 18


udf_Tbl_RowCount can't be used in all situations but most of the time it gives a sufficiently accurate result for managing my databases.


If you like this artile, get one every week with the free T-SQL UDF of the Week Newsletter.


Other 9 submission(s) by this author

 


Report Bad Submission
Use this form to tell us if this entry should be deleted (i.e contains no code, is a virus, etc.).
This submission should be removed because:

Your Vote

What do you think of this article (in the Intermediate category)?
(The article with your highest vote will win this month's coding contest!)
Excellent  Good  Average  Below Average  Poor (See voting log ...)
 

Other User Comments

4/22/2003 8:33:33 AM

Good information but hard to read the way it was displayed. Thanks
(If this comment was disrespectful, please report it.)

 
4/23/2003 12:06:46 PMJames Fleming

In oracle you can just do
select max(rownum) from my_table
of course in SQL server, there's probibly a variation of the syntax to do the same. Also don't do Select count(*) do the count on any indexed field. and remember count ignores nulls.
(If this comment was disrespectful, please report it.)

 
4/28/2003 10:10:41 AMJames Travis

If you have a Clustered index on the Table it will generally run a Clustered Index scan which does have a pretty good bang unlike a Heep table which will perform a Table scan. However, with Sysindexes you have to be real carefull to look at the "rowmodctr", if this number is not 0 then the "rows" value may be inaccurate causing you to misreport your tables count. This is why it is a bad pratice to use system tables, the "rowmodctr" is used in determining the next time a stats update will take place.
(If this comment was disrespectful, please report it.)

 
2/12/2008 2:00:53 PMpranaav

it is too good..
(If this comment was disrespectful, please report it.)

 

Add Your Feedback
Your feedback will be posted below and an email sent to the author. Please remember that the author was kind enough to share this with you, so any criticisms must be stated politely, or they will be deleted. (For feedback not related to this particular article, please click here instead.)
 

To post feedback, first please login.