SQL Server Filtering Index performance - sql-server

Currently have an index like;
CREATE UNIQUE NONCLUSTERED INDEX [CDPAYAPP_INDEX03] ON [dbo].[CDPAYAPP]
(
[CLSVC_ID] ASC,
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90)
Unfortunately, at some of our clients the value for CLSVC_ID can be zero for 100k or more of rows out of a couple million total rows. This cardinality appears to cause the optimizer to occasionally consider the index less than optimal, resulting in table scans. Updating stats multiple times a day can help but not always.
I tried to apply a FILTERING INDEX clause, like;
create UNIQUE NONCLUSTERED index CDPAYAPP_INDEX3A ON CDPAYAPP (CLSVC_ID, ID)
WHERE CLSVC_ID > 0;
But noticed that if I requested any column outside the two index columns it uses the original index not the filtered index. If I only select the columns of the index, it uses the filtered index.
Why?

Related

Add non-null unique constraint - not index

Basically I want to turn this:
ALTER TABLE [dbo].[Computer] ADD CONSTRAINT [AK_ResourceId] UNIQUE NONCLUSTERED
(
[ResourceId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
Into not affecting NULL values. The other posts only give an answer to make a unique index, but an index does not create violation when a duplicate value occurs on INSERT. I want a constraint, but I can't seem to make a WHERE statement on this..
Using SQL Server 2014
Update
It does work with an index after all :)
SQL:
CREATE UNIQUE NONCLUSTERED INDEX IX_ResourceId
ON dbo.Computer(ResourceId)
WHERE ResourceId IS NOT NULL;
This will create the following error:
Cannot insert duplicate key row in object 'dbo.Computer' with unique index 'IX_ResourceId'. The duplicate key value is (1234)

Why FREETEXTTABLE scan entire table if there is a fulltext index available?

There is a simple table of cities
CREATE TABLE [dbo].[cities](
[id] [numeric](6, 0) NOT NULL,
[cityname] [varchar](48) NOT NULL,
)
and a full-text catalog which index not only names of cities:
The table has 6259 rows.
I have a query:
SELECT * FROM FREETEXTTABLE([cities],[cityname],
N'Hello, I am looking for cities inside this text,
my house is not -far from London PJ-')
The results contains 11 rows and the query execution takes about 1-2 seconds.
According to execution plan, 6092 rows were scanned in the index.
Why so many rows are scanned if there is index?
I Use SQL Server 2012.
UPDATE:
There is no special index on table cities. The only index from object explorer looks like:
Create TABLE [dbo].[cities] ADD CONSTRAINT [xpkruianobec] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
GO

Can I have more than one index on a database table?

I have an existing Index on a database table, and I am new to Indexing.
I want to place a Clustered Index on a UniqueID column (the auto-increment column) as there is a lot of data.
Is it okay to have a second index on the table?
Existing Index is on a One To Many Value:
USE [Archive]
GO
/****** Object: Index [IX_CustomerWidget] Script Date: 07/22/2014 16:27:32 ******/
CREATE NONCLUSTERED INDEX [IX_CustomerWidget] ON [dbo].[CustomerWidget]
(
[WidgetID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
Also is there any harm in adding an Index - meaning if it is not right it can be dropped with no harm to the data?
Yes. It is perfectly normal to have a clustered index (the order the data is on disk) and non-clustered indexes to support the queries that are executed against the database, or to enforce unquieness of a column.
For example I might have clustered index on the IdentityID, and a non-clustered index on Date because all my queries look like this: Where Date between #Start and #End.

SQL Server not using index

I'm trying to write a query in SQL Server, but it's doing a table scan on a table with about 30 million rows (TGS_INFO), so the query runs very slowly.
The actual query is more complex but I've reduced it to a simpler version that still exhibits the same issue.
SELECT DISTINCT UNIT_ITEMS.DBKEY,
UNIT_ITEMS.ID,
UNIT_ITEMS.LOCATION1,
UNIT_ITEMS.LOCATION2
FROM UNIT_ITEMS
INNER JOIN TGS.dbo.TGS_INFO
ON UNIT_ITEMS.UNIT_ID = TGS_INFO.UNIT_ID AND
UNIT_ITEMS.ITEM_ID = TGS_INFO.ITEM_ID AND
UNIT_ITEMS.LOCATION1 = TGS_INFO.LOCATION1 AND
UNIT_ITEMS.LOCATION2 = TGS_INFO.LOCATION2
Here is the execution plan.
StmtText
|--Sort(DISTINCT ORDER BY:([DbName].[dbo].[UNIT_ITEMS].[DBKEY] ASC, [DbName].[dbo].[UNIT_ITEMS].[ITEM_ID] ASC, [DbName].[dbo].[UNIT_ITEMS].[LOCATION1] ASC, [DbName].[dbo].[UNIT_ITEMS].[LOCATION2] ASC))
|--Hash Match(Inner Join, HASH:([DbName].[dbo].[UNIT_ITEMS].[UNIT_ID], [DbName].[dbo].[UNIT_ITEMS].[ITEM_ID], [DbName].[dbo].[UNIT_ITEMS].[LOCATION1], [DbName].[dbo].[UNIT_ITEMS].[LOCATION2])=([Expr1008], [Expr1009], [Expr1010], [Expr1011]), RESIDUAL:([DbName].[dbo].[UNIT_ITEMS].[UNIT_ID]=[Expr1008] AND [DbName].[dbo].[UNIT_ITEMS].[ITEM_ID]=[Expr1009] AND [DbName].[dbo].[UNIT_ITEMS].[LOCATION1]=[Expr1010] AND [DbName].[dbo].[UNIT_ITEMS].[LOCATION2]=[Expr1011]))
|--Table Scan(OBJECT:([DbName].[dbo].[UNIT_ITEMS]))
|--Compute Scalar(DEFINE:([Expr1008]=CONVERT_IMPLICIT(int,[TGS].[dbo].[TGS_INFO].[UNIT_ID],0), [Expr1009]=CONVERT_IMPLICIT(nvarchar(50),[TGS].[dbo].[TGS_INFO].[ITEM_ID],0), [Expr1010]=CONVERT_IMPLICIT(nvarchar(50),[TGS].[dbo].[TGS_INFO].[LOCATION1],0), [Expr1011]=CONVERT_IMPLICIT(int,[TGS].[dbo].[TGS_INFO].[LOCATION2],0)))
|--Table Scan(OBJECT:([TGS].[dbo].[TGS_INFO]))
TGS_INFO and UNIT_ITEMS both have nonclustered indexes on UNIT_ID and ITEM_ID. As mentioned, TGS_INFO has about 30 million rows but they are evenly distributed around about a thousand different UNIT_IDs. UNIT_ITEMS always contains only one UNIT_ID.
Here are the indexes:
CREATE NONCLUSTERED INDEX [IX_UNIT_ID_ITEM_ID] ON [dbo].[TGS_INFO]
(
[UNIT_ID] ASC,
[ITEM_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
CREATE NONCLUSTERED INDEX [IX_UNIT_ID_ITEM_ID] ON [dbo].[UNIT_ITEMS]
(
[UNIT_ID] ASC,
[ITEM_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
As I mentioned in the comments, all the columns are VARCHAR(50) in TGS_INFO. All the columns in UNIT_ITEMS are ints.
For the record, I didn't design the schema of TGS_INFO.
If you don't include LOCATION1 and LOCATION2 in your indexes the join cannot be satisfied from an index alone. Add these columns to the indexes on both tables.
You probably have to include all other columns that are referenced in your query, too.
I notice the execution plan shows the following:
|--Compute Scalar(DEFINE:([Expr1008]=CONVERT_IMPLICIT(int,[TGS].[dbo].[TGS_INFO].[UNIT_ID],0), [Expr1009]=CONVERT_IMPLICIT(nvarchar(50),[TGS].[dbo].[TGS_INFO].[ITEM_ID],0), [Expr1010]=CONVERT_IMPLICIT(nvarchar(50),[TGS].[dbo].[TGS_INFO].[LOCATION1],0), [Expr1011]=CONVERT_IMPLICIT(int,[TGS].[dbo].[TGS_INFO].[LOCATION2],0)))
I can't think of a good reason for the query engine to do an implicit data type conversion on these columns unless the data types between the two tables don't match on the columns you're using for the join.
You may also try moving UNIT_ITEMS.LOCATION1 = TGS_INFO.LOCATION1 AND UNIT_ITEMS.LOCATION2 = TGS_INFO.LOCATION2 to the WHERE clause since they're not covered by an index. The query engine is typically smart enough to account for this, but it's something to try.

Filtered non-clustered Index abnormal behaivior

I have a table that created some filtered non-clustered on some columns such:
CREATE UNIQUE NONCLUSTERED INDEX [IX_Sh_Esh] ON [dbo].[My_Tbl]
(
[City_Code] ASC,
[Sh_Esh] ASC
)
WHERE ([Sh_Bod]=(0) AND [Noe_Fa]=(0))
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
and:
CREATE UNIQUE NONCLUSTERED INDEX [IX_Kho] ON [dbo].[My_Tbl]
(
[City_Code] ASC,
[Kho] ASC
)
WHERE ([Sh_Bod]=(0) AND [Sh_Esh]=(0) AND [Noe_Fa]=(1))
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
I create this indexes on my table with no error but when I want to add a new column I get this error:
'My_Tbl' table
- Unable to create index 'IX_Sh_Esh'.
The CREATE UNIQUE INDEX statement terminated because a duplicate key was found for the object name 'My_Tbl' and the index name 'IX_Sh_Esh'. The duplicate key value is (3, 0).
The statement has been terminated.
my table data is:
According to first Index because the rows No. 1 and No. 4 does not satisfy the where cluase should not create index on them.Why I get the above error?
thanks
EDIT 1) :
there is Interesting point.If I delete that index and add the Column(s) then ReCreate that Index,the index create with no error.STRANGE!!!!
The reason you can drop the index and then add the data, then recreate the index is because creating an index does not check existing data, just data that you are trying to insert/update.
You're not getting the error because its a filtered index, you're getting it because its a unique index and you're trying to add duplicate values to the table's column that the unique index is on. That's the beaty of them! If you need duplicate data don't make the index unique.

Resources