Unique filtered index and surprising estimation











up vote
3
down vote

favorite












When I view the estimated execution plan for this query...



SELECT *
FROM tabela2 x
LEFT JOIN dbo.tabela1 t with (nolock) on t.Kod = x.Kod


... the Estimated Number of Rows property for [table1] shows 10. Why is this? In the schema (copied below) I have a unique index AKF_tabela1_Kod. Shouldn't this unique index force the row estimation to be 1?



Estimated Execution Plan



query plan



Create Database, Tables and Index



-- create database 
USE [master]
GO
DROP DATABASE IF EXISTS my_test;
CREATE DATABASE my_test;
GO
ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS OFF;
ALTER AUTHORIZATION ON DATABASE ::my_test TO sa;
USE my_test
GO

-- create dbo.tabela1

CREATE TABLE dbo.[tabela1]
(
[Id] int NOT NULL identity(1,1),
[kol1] varchar(20) NOT NULL,
[Kod] int NULL,
CONSTRAINT [PK_tabela1] PRIMARY KEY NONCLUSTERED([id] ASC) WITH (ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON),
CONSTRAINT [BK_tabela1] UNIQUE CLUSTERED([Kol1] ASC) WITH (ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON),
);
GO

-- create Index

CREATE UNIQUE NONCLUSTERED INDEX [AKF_tabela1_Kod]
ON dbo.[tabela1]([Kod] ASC)
INCLUDE ([id],[kol1])
WHERE ([Kod] IS NOT NULL)
WITH (ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, MAXDOP = 0);
GO

-- create dbo.tabela2

IF OBJECT_ID('dbo.tabela2') IS NULL
CREATE TABLE tabela2 (Kod int NOT NULL)
GO


Insert Data into Table



-- create data in tabela1
declare @i int=1
while @i<=100
begin
INSERT tabela1 (kol1, kod)
values (@i, cast(@i+100 as varchar))
set @i += 1;
end;
GO

UPDATE STATISTICS tabela1 WITH FULLSCAN;


Here the Execution plan










share|improve this question









New contributor




coders is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
















  • 1




    Why is there an exclamation mark in your Index Seek?
    – McNets
    5 hours ago










  • I've checked it on my server and on fiddle and the ENR = 1. The Plan
    – McNets
    5 hours ago










  • Because the automatic statistics creation option has been disabled on the database. If there is a dedicated index filtered (seek) on a column , why do I need the statistics not filtered on the entire column? Rhetorical is the question :). The question is, why SQL Server does not correctly estimate the number of rows based on a unique filtered index? Is this a paradox that uses a unique index and estimates a value greater than 1?
    – coders
    3 hours ago












  • It might be easier for people to answer if you share the execution plan.
    – sp_BlitzErik
    3 hours ago












  • Here you are :) : brentozar.com/pastetheplan/?id=r1oPgB6y4
    – coders
    3 hours ago

















up vote
3
down vote

favorite












When I view the estimated execution plan for this query...



SELECT *
FROM tabela2 x
LEFT JOIN dbo.tabela1 t with (nolock) on t.Kod = x.Kod


... the Estimated Number of Rows property for [table1] shows 10. Why is this? In the schema (copied below) I have a unique index AKF_tabela1_Kod. Shouldn't this unique index force the row estimation to be 1?



Estimated Execution Plan



query plan



Create Database, Tables and Index



-- create database 
USE [master]
GO
DROP DATABASE IF EXISTS my_test;
CREATE DATABASE my_test;
GO
ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS OFF;
ALTER AUTHORIZATION ON DATABASE ::my_test TO sa;
USE my_test
GO

-- create dbo.tabela1

CREATE TABLE dbo.[tabela1]
(
[Id] int NOT NULL identity(1,1),
[kol1] varchar(20) NOT NULL,
[Kod] int NULL,
CONSTRAINT [PK_tabela1] PRIMARY KEY NONCLUSTERED([id] ASC) WITH (ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON),
CONSTRAINT [BK_tabela1] UNIQUE CLUSTERED([Kol1] ASC) WITH (ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON),
);
GO

-- create Index

CREATE UNIQUE NONCLUSTERED INDEX [AKF_tabela1_Kod]
ON dbo.[tabela1]([Kod] ASC)
INCLUDE ([id],[kol1])
WHERE ([Kod] IS NOT NULL)
WITH (ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, MAXDOP = 0);
GO

-- create dbo.tabela2

IF OBJECT_ID('dbo.tabela2') IS NULL
CREATE TABLE tabela2 (Kod int NOT NULL)
GO


Insert Data into Table



-- create data in tabela1
declare @i int=1
while @i<=100
begin
INSERT tabela1 (kol1, kod)
values (@i, cast(@i+100 as varchar))
set @i += 1;
end;
GO

UPDATE STATISTICS tabela1 WITH FULLSCAN;


Here the Execution plan










share|improve this question









New contributor




coders is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
















  • 1




    Why is there an exclamation mark in your Index Seek?
    – McNets
    5 hours ago










  • I've checked it on my server and on fiddle and the ENR = 1. The Plan
    – McNets
    5 hours ago










  • Because the automatic statistics creation option has been disabled on the database. If there is a dedicated index filtered (seek) on a column , why do I need the statistics not filtered on the entire column? Rhetorical is the question :). The question is, why SQL Server does not correctly estimate the number of rows based on a unique filtered index? Is this a paradox that uses a unique index and estimates a value greater than 1?
    – coders
    3 hours ago












  • It might be easier for people to answer if you share the execution plan.
    – sp_BlitzErik
    3 hours ago












  • Here you are :) : brentozar.com/pastetheplan/?id=r1oPgB6y4
    – coders
    3 hours ago















up vote
3
down vote

favorite









up vote
3
down vote

favorite











When I view the estimated execution plan for this query...



SELECT *
FROM tabela2 x
LEFT JOIN dbo.tabela1 t with (nolock) on t.Kod = x.Kod


... the Estimated Number of Rows property for [table1] shows 10. Why is this? In the schema (copied below) I have a unique index AKF_tabela1_Kod. Shouldn't this unique index force the row estimation to be 1?



Estimated Execution Plan



query plan



Create Database, Tables and Index



-- create database 
USE [master]
GO
DROP DATABASE IF EXISTS my_test;
CREATE DATABASE my_test;
GO
ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS OFF;
ALTER AUTHORIZATION ON DATABASE ::my_test TO sa;
USE my_test
GO

-- create dbo.tabela1

CREATE TABLE dbo.[tabela1]
(
[Id] int NOT NULL identity(1,1),
[kol1] varchar(20) NOT NULL,
[Kod] int NULL,
CONSTRAINT [PK_tabela1] PRIMARY KEY NONCLUSTERED([id] ASC) WITH (ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON),
CONSTRAINT [BK_tabela1] UNIQUE CLUSTERED([Kol1] ASC) WITH (ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON),
);
GO

-- create Index

CREATE UNIQUE NONCLUSTERED INDEX [AKF_tabela1_Kod]
ON dbo.[tabela1]([Kod] ASC)
INCLUDE ([id],[kol1])
WHERE ([Kod] IS NOT NULL)
WITH (ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, MAXDOP = 0);
GO

-- create dbo.tabela2

IF OBJECT_ID('dbo.tabela2') IS NULL
CREATE TABLE tabela2 (Kod int NOT NULL)
GO


Insert Data into Table



-- create data in tabela1
declare @i int=1
while @i<=100
begin
INSERT tabela1 (kol1, kod)
values (@i, cast(@i+100 as varchar))
set @i += 1;
end;
GO

UPDATE STATISTICS tabela1 WITH FULLSCAN;


Here the Execution plan










share|improve this question









New contributor




coders is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











When I view the estimated execution plan for this query...



SELECT *
FROM tabela2 x
LEFT JOIN dbo.tabela1 t with (nolock) on t.Kod = x.Kod


... the Estimated Number of Rows property for [table1] shows 10. Why is this? In the schema (copied below) I have a unique index AKF_tabela1_Kod. Shouldn't this unique index force the row estimation to be 1?



Estimated Execution Plan



query plan



Create Database, Tables and Index



-- create database 
USE [master]
GO
DROP DATABASE IF EXISTS my_test;
CREATE DATABASE my_test;
GO
ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS OFF;
ALTER AUTHORIZATION ON DATABASE ::my_test TO sa;
USE my_test
GO

-- create dbo.tabela1

CREATE TABLE dbo.[tabela1]
(
[Id] int NOT NULL identity(1,1),
[kol1] varchar(20) NOT NULL,
[Kod] int NULL,
CONSTRAINT [PK_tabela1] PRIMARY KEY NONCLUSTERED([id] ASC) WITH (ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON),
CONSTRAINT [BK_tabela1] UNIQUE CLUSTERED([Kol1] ASC) WITH (ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON),
);
GO

-- create Index

CREATE UNIQUE NONCLUSTERED INDEX [AKF_tabela1_Kod]
ON dbo.[tabela1]([Kod] ASC)
INCLUDE ([id],[kol1])
WHERE ([Kod] IS NOT NULL)
WITH (ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, MAXDOP = 0);
GO

-- create dbo.tabela2

IF OBJECT_ID('dbo.tabela2') IS NULL
CREATE TABLE tabela2 (Kod int NOT NULL)
GO


Insert Data into Table



-- create data in tabela1
declare @i int=1
while @i<=100
begin
INSERT tabela1 (kol1, kod)
values (@i, cast(@i+100 as varchar))
set @i += 1;
end;
GO

UPDATE STATISTICS tabela1 WITH FULLSCAN;


Here the Execution plan







sql-server execution-plan






share|improve this question









New contributor




coders is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











share|improve this question









New contributor




coders is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









share|improve this question




share|improve this question








edited 2 hours ago









McNets

14k41754




14k41754






New contributor




coders is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









asked 6 hours ago









coders

161




161




New contributor




coders is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





New contributor





coders is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






coders is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.








  • 1




    Why is there an exclamation mark in your Index Seek?
    – McNets
    5 hours ago










  • I've checked it on my server and on fiddle and the ENR = 1. The Plan
    – McNets
    5 hours ago










  • Because the automatic statistics creation option has been disabled on the database. If there is a dedicated index filtered (seek) on a column , why do I need the statistics not filtered on the entire column? Rhetorical is the question :). The question is, why SQL Server does not correctly estimate the number of rows based on a unique filtered index? Is this a paradox that uses a unique index and estimates a value greater than 1?
    – coders
    3 hours ago












  • It might be easier for people to answer if you share the execution plan.
    – sp_BlitzErik
    3 hours ago












  • Here you are :) : brentozar.com/pastetheplan/?id=r1oPgB6y4
    – coders
    3 hours ago
















  • 1




    Why is there an exclamation mark in your Index Seek?
    – McNets
    5 hours ago










  • I've checked it on my server and on fiddle and the ENR = 1. The Plan
    – McNets
    5 hours ago










  • Because the automatic statistics creation option has been disabled on the database. If there is a dedicated index filtered (seek) on a column , why do I need the statistics not filtered on the entire column? Rhetorical is the question :). The question is, why SQL Server does not correctly estimate the number of rows based on a unique filtered index? Is this a paradox that uses a unique index and estimates a value greater than 1?
    – coders
    3 hours ago












  • It might be easier for people to answer if you share the execution plan.
    – sp_BlitzErik
    3 hours ago












  • Here you are :) : brentozar.com/pastetheplan/?id=r1oPgB6y4
    – coders
    3 hours ago










1




1




Why is there an exclamation mark in your Index Seek?
– McNets
5 hours ago




Why is there an exclamation mark in your Index Seek?
– McNets
5 hours ago












I've checked it on my server and on fiddle and the ENR = 1. The Plan
– McNets
5 hours ago




I've checked it on my server and on fiddle and the ENR = 1. The Plan
– McNets
5 hours ago












Because the automatic statistics creation option has been disabled on the database. If there is a dedicated index filtered (seek) on a column , why do I need the statistics not filtered on the entire column? Rhetorical is the question :). The question is, why SQL Server does not correctly estimate the number of rows based on a unique filtered index? Is this a paradox that uses a unique index and estimates a value greater than 1?
– coders
3 hours ago






Because the automatic statistics creation option has been disabled on the database. If there is a dedicated index filtered (seek) on a column , why do I need the statistics not filtered on the entire column? Rhetorical is the question :). The question is, why SQL Server does not correctly estimate the number of rows based on a unique filtered index? Is this a paradox that uses a unique index and estimates a value greater than 1?
– coders
3 hours ago














It might be easier for people to answer if you share the execution plan.
– sp_BlitzErik
3 hours ago






It might be easier for people to answer if you share the execution plan.
– sp_BlitzErik
3 hours ago














Here you are :) : brentozar.com/pastetheplan/?id=r1oPgB6y4
– coders
3 hours ago






Here you are :) : brentozar.com/pastetheplan/?id=r1oPgB6y4
– coders
3 hours ago












1 Answer
1






active

oldest

votes

















up vote
4
down vote














the Estimated Number of Rows property for [table1] shows 10. Why is
this? In the schema (copied below) I have a unique index
AKF_tabela1_Kod. Shouldn't this unique index force the row estimation
to be 1?




The statistics are created when creating the unique index, but as a result of the unique index being filtered, the statistics are also filtered.
(where kod is not null).



As a result, the query as it is cannot use these statistics.



Why?



The Index can be used, but the statistics are not a match for the query.



Even if you do a select on kod:



 select kod from dbo.tabela1 t 
where kod is not null option(recompile)


The statistics are still no match:
enter image description here



If you do a select of the id however:



 select id from dbo.tabela1 t 
where kod is not null option(recompile)


There is a match:



enter image description here



This seems to be buggy with auto create stats:



ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS ON;

select kod from dbo.tabela1 t
where kod is not null option(recompile)


This does not create stats for some reason, but is still able to do the correct estimation.
enter image description here



No new stats:



enter image description here



Re running this:



 ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS OFF;

select kod from dbo.tabela1 t
where kod is not null option(recompile)


Gives the same warning:
enter image description here



This seems to be an issue with auto create statistics being off, even though no stats are created.



I am not sure, but an estimate of 10 might be a 'default' value to use, like when using a table variable.



Workarounds:



1



If you create the next index, the result will be 1 estimated rows



CREATE UNIQUE NONCLUSTERED INDEX [AKF_tabela1_Kod2] 
ON dbo.[tabela1]([Kod] ASC)
INCLUDE ([id])
WITH (ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, MAXDOP = 0);
GO


2



Another route you could take is creating your own statistics:



 create statistics ST_Tablea1_Kod on dbo.tabela1(kod)


Retry the query (with a new execution plan):



SELECT *
FROM tabela2 x
LEFT JOIN dbo.tabela1 t with (nolock) on t.Kod = x.Kod option(recompile)


enter image description hereenter image description here



3



Or ofcourse, enable auto create statistics and rerun the query:



ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS ON;


Update:



The below queries give a stat missing on the first execution, but not on the other two. A statistic was created by auto create stats.



     SELECT *
FROM tabela2 x
LEFT JOIN dbo.tabela1 t with (nolock) on t.Kod = x.Kod option(recompile)
ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS ON;
SELECT *
FROM tabela2 x
LEFT JOIN dbo.tabela1 t with (nolock) on t.Kod = x.Kod option(recompile)
ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS OFF;

SELECT *
FROM tabela2 x
LEFT JOIN dbo.tabela1 t with (nolock) on t.Kod = x.Kod option(recompile)


enter image description here



Dropping the stats and retrying with a select:



     drop statistics  dbo.tabela1.[_WA_Sys_00000003_0EA330E9]

select kod from dbo.tabela1 t
where kod is not null option(recompile)

ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS ON;

select kod from dbo.tabela1 t
where kod is not null option(recompile)

ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS OFF;

select kod from dbo.tabela1 t
where kod is not null option(recompile)


Does not generate stats, and gives the same missing index hints on the first and third execution:



enter image description here



I thought that this maybe was because of the optimization level being trivial. But this was not the case.



StatementOptmLevel="TRIVIAL"


Non trivial optimization level:



 select kod from dbo.tabela1 t 
where kod is not null
group by kod option(recompile)

ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS ON;

select kod from dbo.tabela1 t
where kod is not null group by kod option(recompile)

ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS OFF;

select kod from dbo.tabela1 t
where kod is not null group by kod option(recompile)


Result:
enter image description here



Query #2 with automatic stat creation:
enter image description here
(I added 100 rows for a total of 200)



Query #3 , after putting automatic stat creation off again:
enter image description here
(180 estimated rows)






share|improve this answer























  • Did you refresh the statistics branch? (Right-click | Refresh) Just asking. I've had friends that were missing whole database, because they didn't refresh the branch in SSMS.
    – hot2use
    1 hour ago










  • I think (not very scientific i know) i did. But even if i didn't, after setting auto create stats off again, it should still give the result without the warning right? You might actually be correct, Im going to have to check again when i get home and correct any mistakes
    – Randi Vertongen
    1 hour ago










  • There where no stats created on the simple select. These plans are trivial however, which might be the explanation.
    – Randi Vertongen
    9 mins ago










  • @RandiVertongen you can add a silly subquery in a where clause to get full optimization (WHERE 1 = (SELECT 1)). See here for more info.
    – jadarnel27
    5 mins ago












  • Thanks Jadarnel27, i added a group by to force the optimization, still the same issue found.
    – Randi Vertongen
    2 mins ago













Your Answer








StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "182"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});






coders is a new contributor. Be nice, and check out our Code of Conduct.










draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fdba.stackexchange.com%2fquestions%2f224640%2funique-filtered-index-and-surprising-estimation%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
4
down vote














the Estimated Number of Rows property for [table1] shows 10. Why is
this? In the schema (copied below) I have a unique index
AKF_tabela1_Kod. Shouldn't this unique index force the row estimation
to be 1?




The statistics are created when creating the unique index, but as a result of the unique index being filtered, the statistics are also filtered.
(where kod is not null).



As a result, the query as it is cannot use these statistics.



Why?



The Index can be used, but the statistics are not a match for the query.



Even if you do a select on kod:



 select kod from dbo.tabela1 t 
where kod is not null option(recompile)


The statistics are still no match:
enter image description here



If you do a select of the id however:



 select id from dbo.tabela1 t 
where kod is not null option(recompile)


There is a match:



enter image description here



This seems to be buggy with auto create stats:



ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS ON;

select kod from dbo.tabela1 t
where kod is not null option(recompile)


This does not create stats for some reason, but is still able to do the correct estimation.
enter image description here



No new stats:



enter image description here



Re running this:



 ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS OFF;

select kod from dbo.tabela1 t
where kod is not null option(recompile)


Gives the same warning:
enter image description here



This seems to be an issue with auto create statistics being off, even though no stats are created.



I am not sure, but an estimate of 10 might be a 'default' value to use, like when using a table variable.



Workarounds:



1



If you create the next index, the result will be 1 estimated rows



CREATE UNIQUE NONCLUSTERED INDEX [AKF_tabela1_Kod2] 
ON dbo.[tabela1]([Kod] ASC)
INCLUDE ([id])
WITH (ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, MAXDOP = 0);
GO


2



Another route you could take is creating your own statistics:



 create statistics ST_Tablea1_Kod on dbo.tabela1(kod)


Retry the query (with a new execution plan):



SELECT *
FROM tabela2 x
LEFT JOIN dbo.tabela1 t with (nolock) on t.Kod = x.Kod option(recompile)


enter image description hereenter image description here



3



Or ofcourse, enable auto create statistics and rerun the query:



ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS ON;


Update:



The below queries give a stat missing on the first execution, but not on the other two. A statistic was created by auto create stats.



     SELECT *
FROM tabela2 x
LEFT JOIN dbo.tabela1 t with (nolock) on t.Kod = x.Kod option(recompile)
ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS ON;
SELECT *
FROM tabela2 x
LEFT JOIN dbo.tabela1 t with (nolock) on t.Kod = x.Kod option(recompile)
ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS OFF;

SELECT *
FROM tabela2 x
LEFT JOIN dbo.tabela1 t with (nolock) on t.Kod = x.Kod option(recompile)


enter image description here



Dropping the stats and retrying with a select:



     drop statistics  dbo.tabela1.[_WA_Sys_00000003_0EA330E9]

select kod from dbo.tabela1 t
where kod is not null option(recompile)

ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS ON;

select kod from dbo.tabela1 t
where kod is not null option(recompile)

ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS OFF;

select kod from dbo.tabela1 t
where kod is not null option(recompile)


Does not generate stats, and gives the same missing index hints on the first and third execution:



enter image description here



I thought that this maybe was because of the optimization level being trivial. But this was not the case.



StatementOptmLevel="TRIVIAL"


Non trivial optimization level:



 select kod from dbo.tabela1 t 
where kod is not null
group by kod option(recompile)

ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS ON;

select kod from dbo.tabela1 t
where kod is not null group by kod option(recompile)

ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS OFF;

select kod from dbo.tabela1 t
where kod is not null group by kod option(recompile)


Result:
enter image description here



Query #2 with automatic stat creation:
enter image description here
(I added 100 rows for a total of 200)



Query #3 , after putting automatic stat creation off again:
enter image description here
(180 estimated rows)






share|improve this answer























  • Did you refresh the statistics branch? (Right-click | Refresh) Just asking. I've had friends that were missing whole database, because they didn't refresh the branch in SSMS.
    – hot2use
    1 hour ago










  • I think (not very scientific i know) i did. But even if i didn't, after setting auto create stats off again, it should still give the result without the warning right? You might actually be correct, Im going to have to check again when i get home and correct any mistakes
    – Randi Vertongen
    1 hour ago










  • There where no stats created on the simple select. These plans are trivial however, which might be the explanation.
    – Randi Vertongen
    9 mins ago










  • @RandiVertongen you can add a silly subquery in a where clause to get full optimization (WHERE 1 = (SELECT 1)). See here for more info.
    – jadarnel27
    5 mins ago












  • Thanks Jadarnel27, i added a group by to force the optimization, still the same issue found.
    – Randi Vertongen
    2 mins ago

















up vote
4
down vote














the Estimated Number of Rows property for [table1] shows 10. Why is
this? In the schema (copied below) I have a unique index
AKF_tabela1_Kod. Shouldn't this unique index force the row estimation
to be 1?




The statistics are created when creating the unique index, but as a result of the unique index being filtered, the statistics are also filtered.
(where kod is not null).



As a result, the query as it is cannot use these statistics.



Why?



The Index can be used, but the statistics are not a match for the query.



Even if you do a select on kod:



 select kod from dbo.tabela1 t 
where kod is not null option(recompile)


The statistics are still no match:
enter image description here



If you do a select of the id however:



 select id from dbo.tabela1 t 
where kod is not null option(recompile)


There is a match:



enter image description here



This seems to be buggy with auto create stats:



ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS ON;

select kod from dbo.tabela1 t
where kod is not null option(recompile)


This does not create stats for some reason, but is still able to do the correct estimation.
enter image description here



No new stats:



enter image description here



Re running this:



 ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS OFF;

select kod from dbo.tabela1 t
where kod is not null option(recompile)


Gives the same warning:
enter image description here



This seems to be an issue with auto create statistics being off, even though no stats are created.



I am not sure, but an estimate of 10 might be a 'default' value to use, like when using a table variable.



Workarounds:



1



If you create the next index, the result will be 1 estimated rows



CREATE UNIQUE NONCLUSTERED INDEX [AKF_tabela1_Kod2] 
ON dbo.[tabela1]([Kod] ASC)
INCLUDE ([id])
WITH (ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, MAXDOP = 0);
GO


2



Another route you could take is creating your own statistics:



 create statistics ST_Tablea1_Kod on dbo.tabela1(kod)


Retry the query (with a new execution plan):



SELECT *
FROM tabela2 x
LEFT JOIN dbo.tabela1 t with (nolock) on t.Kod = x.Kod option(recompile)


enter image description hereenter image description here



3



Or ofcourse, enable auto create statistics and rerun the query:



ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS ON;


Update:



The below queries give a stat missing on the first execution, but not on the other two. A statistic was created by auto create stats.



     SELECT *
FROM tabela2 x
LEFT JOIN dbo.tabela1 t with (nolock) on t.Kod = x.Kod option(recompile)
ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS ON;
SELECT *
FROM tabela2 x
LEFT JOIN dbo.tabela1 t with (nolock) on t.Kod = x.Kod option(recompile)
ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS OFF;

SELECT *
FROM tabela2 x
LEFT JOIN dbo.tabela1 t with (nolock) on t.Kod = x.Kod option(recompile)


enter image description here



Dropping the stats and retrying with a select:



     drop statistics  dbo.tabela1.[_WA_Sys_00000003_0EA330E9]

select kod from dbo.tabela1 t
where kod is not null option(recompile)

ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS ON;

select kod from dbo.tabela1 t
where kod is not null option(recompile)

ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS OFF;

select kod from dbo.tabela1 t
where kod is not null option(recompile)


Does not generate stats, and gives the same missing index hints on the first and third execution:



enter image description here



I thought that this maybe was because of the optimization level being trivial. But this was not the case.



StatementOptmLevel="TRIVIAL"


Non trivial optimization level:



 select kod from dbo.tabela1 t 
where kod is not null
group by kod option(recompile)

ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS ON;

select kod from dbo.tabela1 t
where kod is not null group by kod option(recompile)

ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS OFF;

select kod from dbo.tabela1 t
where kod is not null group by kod option(recompile)


Result:
enter image description here



Query #2 with automatic stat creation:
enter image description here
(I added 100 rows for a total of 200)



Query #3 , after putting automatic stat creation off again:
enter image description here
(180 estimated rows)






share|improve this answer























  • Did you refresh the statistics branch? (Right-click | Refresh) Just asking. I've had friends that were missing whole database, because they didn't refresh the branch in SSMS.
    – hot2use
    1 hour ago










  • I think (not very scientific i know) i did. But even if i didn't, after setting auto create stats off again, it should still give the result without the warning right? You might actually be correct, Im going to have to check again when i get home and correct any mistakes
    – Randi Vertongen
    1 hour ago










  • There where no stats created on the simple select. These plans are trivial however, which might be the explanation.
    – Randi Vertongen
    9 mins ago










  • @RandiVertongen you can add a silly subquery in a where clause to get full optimization (WHERE 1 = (SELECT 1)). See here for more info.
    – jadarnel27
    5 mins ago












  • Thanks Jadarnel27, i added a group by to force the optimization, still the same issue found.
    – Randi Vertongen
    2 mins ago















up vote
4
down vote










up vote
4
down vote










the Estimated Number of Rows property for [table1] shows 10. Why is
this? In the schema (copied below) I have a unique index
AKF_tabela1_Kod. Shouldn't this unique index force the row estimation
to be 1?




The statistics are created when creating the unique index, but as a result of the unique index being filtered, the statistics are also filtered.
(where kod is not null).



As a result, the query as it is cannot use these statistics.



Why?



The Index can be used, but the statistics are not a match for the query.



Even if you do a select on kod:



 select kod from dbo.tabela1 t 
where kod is not null option(recompile)


The statistics are still no match:
enter image description here



If you do a select of the id however:



 select id from dbo.tabela1 t 
where kod is not null option(recompile)


There is a match:



enter image description here



This seems to be buggy with auto create stats:



ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS ON;

select kod from dbo.tabela1 t
where kod is not null option(recompile)


This does not create stats for some reason, but is still able to do the correct estimation.
enter image description here



No new stats:



enter image description here



Re running this:



 ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS OFF;

select kod from dbo.tabela1 t
where kod is not null option(recompile)


Gives the same warning:
enter image description here



This seems to be an issue with auto create statistics being off, even though no stats are created.



I am not sure, but an estimate of 10 might be a 'default' value to use, like when using a table variable.



Workarounds:



1



If you create the next index, the result will be 1 estimated rows



CREATE UNIQUE NONCLUSTERED INDEX [AKF_tabela1_Kod2] 
ON dbo.[tabela1]([Kod] ASC)
INCLUDE ([id])
WITH (ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, MAXDOP = 0);
GO


2



Another route you could take is creating your own statistics:



 create statistics ST_Tablea1_Kod on dbo.tabela1(kod)


Retry the query (with a new execution plan):



SELECT *
FROM tabela2 x
LEFT JOIN dbo.tabela1 t with (nolock) on t.Kod = x.Kod option(recompile)


enter image description hereenter image description here



3



Or ofcourse, enable auto create statistics and rerun the query:



ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS ON;


Update:



The below queries give a stat missing on the first execution, but not on the other two. A statistic was created by auto create stats.



     SELECT *
FROM tabela2 x
LEFT JOIN dbo.tabela1 t with (nolock) on t.Kod = x.Kod option(recompile)
ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS ON;
SELECT *
FROM tabela2 x
LEFT JOIN dbo.tabela1 t with (nolock) on t.Kod = x.Kod option(recompile)
ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS OFF;

SELECT *
FROM tabela2 x
LEFT JOIN dbo.tabela1 t with (nolock) on t.Kod = x.Kod option(recompile)


enter image description here



Dropping the stats and retrying with a select:



     drop statistics  dbo.tabela1.[_WA_Sys_00000003_0EA330E9]

select kod from dbo.tabela1 t
where kod is not null option(recompile)

ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS ON;

select kod from dbo.tabela1 t
where kod is not null option(recompile)

ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS OFF;

select kod from dbo.tabela1 t
where kod is not null option(recompile)


Does not generate stats, and gives the same missing index hints on the first and third execution:



enter image description here



I thought that this maybe was because of the optimization level being trivial. But this was not the case.



StatementOptmLevel="TRIVIAL"


Non trivial optimization level:



 select kod from dbo.tabela1 t 
where kod is not null
group by kod option(recompile)

ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS ON;

select kod from dbo.tabela1 t
where kod is not null group by kod option(recompile)

ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS OFF;

select kod from dbo.tabela1 t
where kod is not null group by kod option(recompile)


Result:
enter image description here



Query #2 with automatic stat creation:
enter image description here
(I added 100 rows for a total of 200)



Query #3 , after putting automatic stat creation off again:
enter image description here
(180 estimated rows)






share|improve this answer















the Estimated Number of Rows property for [table1] shows 10. Why is
this? In the schema (copied below) I have a unique index
AKF_tabela1_Kod. Shouldn't this unique index force the row estimation
to be 1?




The statistics are created when creating the unique index, but as a result of the unique index being filtered, the statistics are also filtered.
(where kod is not null).



As a result, the query as it is cannot use these statistics.



Why?



The Index can be used, but the statistics are not a match for the query.



Even if you do a select on kod:



 select kod from dbo.tabela1 t 
where kod is not null option(recompile)


The statistics are still no match:
enter image description here



If you do a select of the id however:



 select id from dbo.tabela1 t 
where kod is not null option(recompile)


There is a match:



enter image description here



This seems to be buggy with auto create stats:



ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS ON;

select kod from dbo.tabela1 t
where kod is not null option(recompile)


This does not create stats for some reason, but is still able to do the correct estimation.
enter image description here



No new stats:



enter image description here



Re running this:



 ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS OFF;

select kod from dbo.tabela1 t
where kod is not null option(recompile)


Gives the same warning:
enter image description here



This seems to be an issue with auto create statistics being off, even though no stats are created.



I am not sure, but an estimate of 10 might be a 'default' value to use, like when using a table variable.



Workarounds:



1



If you create the next index, the result will be 1 estimated rows



CREATE UNIQUE NONCLUSTERED INDEX [AKF_tabela1_Kod2] 
ON dbo.[tabela1]([Kod] ASC)
INCLUDE ([id])
WITH (ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, MAXDOP = 0);
GO


2



Another route you could take is creating your own statistics:



 create statistics ST_Tablea1_Kod on dbo.tabela1(kod)


Retry the query (with a new execution plan):



SELECT *
FROM tabela2 x
LEFT JOIN dbo.tabela1 t with (nolock) on t.Kod = x.Kod option(recompile)


enter image description hereenter image description here



3



Or ofcourse, enable auto create statistics and rerun the query:



ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS ON;


Update:



The below queries give a stat missing on the first execution, but not on the other two. A statistic was created by auto create stats.



     SELECT *
FROM tabela2 x
LEFT JOIN dbo.tabela1 t with (nolock) on t.Kod = x.Kod option(recompile)
ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS ON;
SELECT *
FROM tabela2 x
LEFT JOIN dbo.tabela1 t with (nolock) on t.Kod = x.Kod option(recompile)
ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS OFF;

SELECT *
FROM tabela2 x
LEFT JOIN dbo.tabela1 t with (nolock) on t.Kod = x.Kod option(recompile)


enter image description here



Dropping the stats and retrying with a select:



     drop statistics  dbo.tabela1.[_WA_Sys_00000003_0EA330E9]

select kod from dbo.tabela1 t
where kod is not null option(recompile)

ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS ON;

select kod from dbo.tabela1 t
where kod is not null option(recompile)

ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS OFF;

select kod from dbo.tabela1 t
where kod is not null option(recompile)


Does not generate stats, and gives the same missing index hints on the first and third execution:



enter image description here



I thought that this maybe was because of the optimization level being trivial. But this was not the case.



StatementOptmLevel="TRIVIAL"


Non trivial optimization level:



 select kod from dbo.tabela1 t 
where kod is not null
group by kod option(recompile)

ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS ON;

select kod from dbo.tabela1 t
where kod is not null group by kod option(recompile)

ALTER DATABASE my_test SET AUTO_CREATE_STATISTICS OFF;

select kod from dbo.tabela1 t
where kod is not null group by kod option(recompile)


Result:
enter image description here



Query #2 with automatic stat creation:
enter image description here
(I added 100 rows for a total of 200)



Query #3 , after putting automatic stat creation off again:
enter image description here
(180 estimated rows)







share|improve this answer














share|improve this answer



share|improve this answer








edited 2 mins ago

























answered 2 hours ago









Randi Vertongen

78011




78011












  • Did you refresh the statistics branch? (Right-click | Refresh) Just asking. I've had friends that were missing whole database, because they didn't refresh the branch in SSMS.
    – hot2use
    1 hour ago










  • I think (not very scientific i know) i did. But even if i didn't, after setting auto create stats off again, it should still give the result without the warning right? You might actually be correct, Im going to have to check again when i get home and correct any mistakes
    – Randi Vertongen
    1 hour ago










  • There where no stats created on the simple select. These plans are trivial however, which might be the explanation.
    – Randi Vertongen
    9 mins ago










  • @RandiVertongen you can add a silly subquery in a where clause to get full optimization (WHERE 1 = (SELECT 1)). See here for more info.
    – jadarnel27
    5 mins ago












  • Thanks Jadarnel27, i added a group by to force the optimization, still the same issue found.
    – Randi Vertongen
    2 mins ago




















  • Did you refresh the statistics branch? (Right-click | Refresh) Just asking. I've had friends that were missing whole database, because they didn't refresh the branch in SSMS.
    – hot2use
    1 hour ago










  • I think (not very scientific i know) i did. But even if i didn't, after setting auto create stats off again, it should still give the result without the warning right? You might actually be correct, Im going to have to check again when i get home and correct any mistakes
    – Randi Vertongen
    1 hour ago










  • There where no stats created on the simple select. These plans are trivial however, which might be the explanation.
    – Randi Vertongen
    9 mins ago










  • @RandiVertongen you can add a silly subquery in a where clause to get full optimization (WHERE 1 = (SELECT 1)). See here for more info.
    – jadarnel27
    5 mins ago












  • Thanks Jadarnel27, i added a group by to force the optimization, still the same issue found.
    – Randi Vertongen
    2 mins ago


















Did you refresh the statistics branch? (Right-click | Refresh) Just asking. I've had friends that were missing whole database, because they didn't refresh the branch in SSMS.
– hot2use
1 hour ago




Did you refresh the statistics branch? (Right-click | Refresh) Just asking. I've had friends that were missing whole database, because they didn't refresh the branch in SSMS.
– hot2use
1 hour ago












I think (not very scientific i know) i did. But even if i didn't, after setting auto create stats off again, it should still give the result without the warning right? You might actually be correct, Im going to have to check again when i get home and correct any mistakes
– Randi Vertongen
1 hour ago




I think (not very scientific i know) i did. But even if i didn't, after setting auto create stats off again, it should still give the result without the warning right? You might actually be correct, Im going to have to check again when i get home and correct any mistakes
– Randi Vertongen
1 hour ago












There where no stats created on the simple select. These plans are trivial however, which might be the explanation.
– Randi Vertongen
9 mins ago




There where no stats created on the simple select. These plans are trivial however, which might be the explanation.
– Randi Vertongen
9 mins ago












@RandiVertongen you can add a silly subquery in a where clause to get full optimization (WHERE 1 = (SELECT 1)). See here for more info.
– jadarnel27
5 mins ago






@RandiVertongen you can add a silly subquery in a where clause to get full optimization (WHERE 1 = (SELECT 1)). See here for more info.
– jadarnel27
5 mins ago














Thanks Jadarnel27, i added a group by to force the optimization, still the same issue found.
– Randi Vertongen
2 mins ago






Thanks Jadarnel27, i added a group by to force the optimization, still the same issue found.
– Randi Vertongen
2 mins ago












coders is a new contributor. Be nice, and check out our Code of Conduct.










draft saved

draft discarded


















coders is a new contributor. Be nice, and check out our Code of Conduct.













coders is a new contributor. Be nice, and check out our Code of Conduct.












coders is a new contributor. Be nice, and check out our Code of Conduct.
















Thanks for contributing an answer to Database Administrators Stack Exchange!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fdba.stackexchange.com%2fquestions%2f224640%2funique-filtered-index-and-surprising-estimation%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

What visual should I use to simply compare current year value vs last year in Power BI desktop

How to ignore python UserWarning in pytest?

Alexandru Averescu