Indexing Views

Recently while creating an archival job I noticed that job was taking way too long to complete. To help troubleshoot I executed the stored procedure directly and it was also taking a long time to fetch the rows from the view that I was using.   Based on the query plan it looked like creating an index on the view may help the issue, so I first looked to see if any indexes were in place for the views, but none were found.  The next step was to create an index on the view, but I was presented with this error message “Cannot create index on view, because the view is not schema bound”.

The error message “Cannot create index on view ‘*’ because the view is not schema bound. (Microsoft SQL Server, Error: 1939)” clearly suggested that in order to create an index on this view I have to make it schema bound, but what is schema binding and how does this work?  Schema binding ties an object to the base object that this new object depends upon.  So without schema binding if a view is created and the underlying table is changed, the view may break, but the table change can still occur.  With schema binding, if the base object is bound to another object, you will not be able to modify the based object unless you drop or alter the object to remove the schema binding.

So below shows what happened when I tried to create an index on the view I was using.

In SQL Server, views are not bound to the schema of the base tables by default. In such case we may change the schema of the base table at any time, regardless of the fact that the associated view may or may not work with the new schema. We can even drop the underlying table while keeping the associated view without any warning. In this case when the view is used, we will get an invalid object name error for the base table.

So if you want to create an index on a view or you want to preserve the base table schema once a view has been defined, in both these cases you have to use the “WITH SCHEMABINDING” clause to bind the view to the schema of the base tables.

To use schema binding for views, first we will create a sample table in AdventureWorks database then a view “vw_sampleView” is created on this new table.

Create sample table and sample view
USE AdventureWorks
SELECT * INTO SampleTable
FROM sales.SalesOrderDetail
SELECT salesorderid, productid, unitprice, linetotal, rowguid,modifieddate

--If the view already existed we could use this to add SCHEMABINDING
SELECT salesorderid, productid, unitprice, linetotal, rowguid,modifieddate

Be aware that if you do not use the schema name, (dbo) in this case, then you will get the following error while creating the view. “Cannot schema bind view ‘dbo.vw_sampleView’ because name ‘SAMPLETABLE’ is invalid for schema binding. Names must be in two-part format and an object cannot reference itself.”

This error is only generated in case of schema bound views. In the case of ordinary views you will not get this error.

So here we are with a SCHEMABOUND view “sampleView” on base table “sampleTable”. Now we will check that we are able to create an index on the view.

In the following screenshot we are trying to create a non-clustered index on the view and we get the following error:

An important point to note is that you must first create a unique clustered index on the view, before you can create any non-clustered indexes.  The script below shows us how we can create this unique clustered index or you can do this via SQL Server Management Studio (SSMS).

Create Unique clustered index on view
CREATE UNIQUE CLUSTERED INDEX [TestIndex] ON [dbo].[vw_sampleView]
[rowguid] ASC

When this is run the command successfully creates the unique clustered index “TestIndex” on “vw_sampleview”. At this point we can add any additional indexes as needed.

Here are some things to consider:

  • You can not create an index on a view with outer joins used in it, even if you use schema binding
  • You can not use ‘*’ in the select statement of a view when it is schema bound. In such case you will clearly get error message of level 15 as “Syntax ‘*’ is not allowed in schema-bound objects.”.
  • You will not be able to create clustered index on a view if the view references any nondeterministic functions.
  • You can not use aggregate functions when using schema binding.
  • You can not migrate the base table of a schema bound view.

Now we are left with our second part of the problem, how schema preservation is implemented for the base table.  Again we have our “sampleTable” and “vw_sampleView” with schema binding. We know that without schema binding there was no issue to alter or drop the base table without any type of warning or error. Now if we try to alter the table structure or drop the table, we are going to get this error message.

By using SSMS to alter the data type of a column in the base table”sampleTable”, I get a warning message notifying me that because of the schema bound view this will not work.

To change the base table we need to remove the SCHEMABINDING option from our objects or drop and recreate these objects once the table has been altered.

On the other hand schema binding does not implement any restriction on the alteration of the view. You may alter or drop the view the same way as you normally would.

Next Steps

  • If you are having poor performance when using views, look at creating indexes on the views

  • One of the criteria for indexed views is to use the schema binding option.  When objects are schema bound this also reduces the accidental dropping or altering of objects that are required in your database.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s