Mi. Sharp Mi. Sharp - 23 days ago 7
C# Question

EntityFramework 6 model generation very slow with SQL-Server 2016

I use Visual Studio 2015 Professional with Sql Server 2016 and EntityFramework 6.
After wondering about the slow performance of model generation I found in the class EntityStoreSchemaGeneratorDatabaseSchemaLoader the method

IEnumerable<DataRow> LoadDataTable
.

The execution of the command need sometimes more than 2 minutes, whereas with older versions of sql server it takes milliseconds.

using (EntityCommand command = CreateFilteredCommand(_connection, sql, null, queryTypes, new List<EntityStoreSchemaFilterEntry>(filters), filterAliases))
{
using (DbDataReader reader = command.ExecuteReader(CommandBehavior.SequentialAccess))
...


Does anyone know, why the ExecuteReader is so extremly slow? It is not a problem with CPU or memory. Maybe it is important to say, that SQL-Server 2016 runs in VM-Ware!

UPDATE
This statements runs for minutes in SQL-Server 2016, in 2012 it takes milliseconds.

exec sp_executesql N'SELECT
[UnionAll1].[Ordinal] AS [C1],
[Extent1].[CatalogName] AS [CatalogName],
[Extent1].[SchemaName] AS [SchemaName],
[Extent1].[Name] AS [Name],
[UnionAll1].[Name] AS [C2],
[UnionAll1].[IsNullable] AS [C3],
[UnionAll1].[TypeName] AS [C4],
[UnionAll1].[MaxLength] AS [C5],
[UnionAll1].[Precision] AS [C6],
[UnionAll1].[DateTimePrecision] AS [C7],
[UnionAll1].[Scale] AS [C8],
[UnionAll1].[IsIdentity] AS [C9],
[UnionAll1].[IsStoreGenerated] AS [C10],
CASE WHEN ([Project5].[C2] IS NULL) THEN cast(0 as bit) ELSE [Project5].[C2] END AS [C11]
FROM (
SELECT
quotename(TABLE_SCHEMA) + quotename(TABLE_NAME) [Id]
, TABLE_CATALOG [CatalogName]
, TABLE_SCHEMA [SchemaName]
, TABLE_NAME [Name]
FROM
INFORMATION_SCHEMA.TABLES
WHERE
TABLE_TYPE = ''BASE TABLE''
) AS [Extent1]
INNER JOIN (SELECT
[Extent2].[Id] AS [Id],
[Extent2].[Name] AS [Name],
[Extent2].[Ordinal] AS [Ordinal],
[Extent2].[IsNullable] AS [IsNullable],
[Extent2].[TypeName] AS [TypeName],
[Extent2].[MaxLength] AS [MaxLength],
[Extent2].[Precision] AS [Precision],
[Extent2].[DateTimePrecision] AS [DateTimePrecision],
[Extent2].[Scale] AS [Scale],
[Extent2].[IsIdentity] AS [IsIdentity],
[Extent2].[IsStoreGenerated] AS [IsStoreGenerated],
0 AS [C1],
[Extent2].[ParentId] AS [ParentId]
FROM (
SELECT
quotename(c.TABLE_SCHEMA) + quotename(c.TABLE_NAME) + quotename(c.COLUMN_NAME) [Id]
, quotename(c.TABLE_SCHEMA) + quotename(c.TABLE_NAME) [ParentId]
, c.COLUMN_NAME [Name]
, c.ORDINAL_POSITION [Ordinal]
, CAST( CASE c.IS_NULLABLE WHEN ''YES'' THEN 1 WHEN ''NO'' THEN 0 ELSE 0 END as bit) [IsNullable]
, CASE
WHEN c.DATA_TYPE in (''varchar'', ''nvarchar'', ''varbinary'') and
c.CHARACTER_MAXIMUM_LENGTH = -1 THEN
c.DATA_TYPE + ''(max)''
ELSE
c.DATA_TYPE
END
as [TypeName]
, c.CHARACTER_MAXIMUM_LENGTH [MaxLength]
, CAST(c.NUMERIC_PRECISION as integer) [Precision]
, CAST(c.DATETIME_PRECISION as integer)[DateTimePrecision]
, CAST(c.NUMERIC_SCALE as integer) [Scale]
, c.COLLATION_CATALOG [CollationCatalog]
, c.COLLATION_SCHEMA [CollationSchema]
, c.COLLATION_NAME [CollationName]
, c.CHARACTER_SET_CATALOG [CharacterSetCatalog]
, c.CHARACTER_SET_SCHEMA [CharacterSetSchema]
, c.CHARACTER_SET_NAME [CharacterSetName]
, CAST(0 as bit) as [IsMultiSet]
, CAST(columnproperty( object_id(quotename(c.TABLE_SCHEMA) + ''.'' + quotename(c.TABLE_NAME)), c.COLUMN_NAME, ''IsIdentity'' ) as bit) as [IsIdentity]
, CAST(columnproperty( object_id(quotename(c.TABLE_SCHEMA) + ''.'' + quotename(c.TABLE_NAME)), c.COLUMN_NAME, ''IsComputed'' ) | CASE WHEN c.DATA_TYPE = ''timestamp'' THEN 1 ELSE 0 END as bit) as [IsStoreGenerated]
, c.COLUMN_DEFAULT as [Default]
FROM
INFORMATION_SCHEMA.COLUMNS c
INNER JOIN
INFORMATION_SCHEMA.TABLES t ON
c.TABLE_CATALOG = t.TABLE_CATALOG AND
c.TABLE_SCHEMA = t.TABLE_SCHEMA AND
c.TABLE_NAME = t.TABLE_NAME AND
t.TABLE_TYPE = ''BASE TABLE''
) AS [Extent2]
UNION ALL
SELECT
[Extent3].[Id] AS [Id],
[Extent3].[Name] AS [Name],
[Extent3].[Ordinal] AS [Ordinal],
[Extent3].[IsNullable] AS [IsNullable],
[Extent3].[TypeName] AS [TypeName],
[Extent3].[MaxLength] AS [MaxLength],
[Extent3].[Precision] AS [Precision],
[Extent3].[DateTimePrecision] AS [DateTimePrecision],
[Extent3].[Scale] AS [Scale],
[Extent3].[IsIdentity] AS [IsIdentity],
[Extent3].[IsStoreGenerated] AS [IsStoreGenerated],
6 AS [C1],
[Extent3].[ParentId] AS [ParentId]
FROM (
SELECT
quotename(c.TABLE_SCHEMA) + quotename(c.TABLE_NAME) + quotename(c.COLUMN_NAME) [Id]
, quotename(c.TABLE_SCHEMA) + quotename(c.TABLE_NAME) [ParentId]
, c.COLUMN_NAME [Name]
, c.ORDINAL_POSITION [Ordinal]
, CAST( CASE c.IS_NULLABLE WHEN ''YES'' THEN 1 WHEN ''NO'' THEN 0 ELSE 0 END as bit) [IsNullable]
, CASE
WHEN c.DATA_TYPE in (''varchar'', ''nvarchar'', ''varbinary'') and
c.CHARACTER_MAXIMUM_LENGTH = -1 THEN
c.DATA_TYPE + ''(max)''
ELSE
c.DATA_TYPE
END
as [TypeName]
, c.CHARACTER_MAXIMUM_LENGTH [MaxLength]
, CAST(c.NUMERIC_PRECISION as integer) [Precision]
, CAST(c.DATETIME_PRECISION as integer) as [DateTimePrecision]
, CAST(c.NUMERIC_SCALE as integer) [Scale]
, c.COLLATION_CATALOG [CollationCatalog]
, c.COLLATION_SCHEMA [CollationSchema]
, c.COLLATION_NAME [CollationName]
, c.CHARACTER_SET_CATALOG [CharacterSetCatalog]
, c.CHARACTER_SET_SCHEMA [CharacterSetSchema]
, c.CHARACTER_SET_NAME [CharacterSetName]
, CAST(0 as bit) as [IsMultiSet]
, CAST(columnproperty( object_id(quotename(c.TABLE_SCHEMA) + ''.'' + quotename(c.TABLE_NAME)), c.COLUMN_NAME, ''IsIdentity'' ) as bit) as [IsIdentity]
, CAST(columnproperty( object_id(quotename(c.TABLE_SCHEMA) + ''.'' + quotename(c.TABLE_NAME)), c.COLUMN_NAME, ''IsComputed'' ) | CASE WHEN c.DATA_TYPE = ''timestamp'' THEN 1 ELSE 0 END as bit) as [IsStoreGenerated]
, c.COLUMN_DEFAULT [Default]
FROM
INFORMATION_SCHEMA.COLUMNS c
INNER JOIN
INFORMATION_SCHEMA.VIEWS v ON
c.TABLE_CATALOG = v.TABLE_CATALOG AND
c.TABLE_SCHEMA = v.TABLE_SCHEMA AND
c.TABLE_NAME = v.TABLE_NAME
WHERE
NOT (v.TABLE_SCHEMA = ''dbo''
AND v.TABLE_NAME in(''syssegments'', ''sysconstraints'')
AND SUBSTRING(CAST(SERVERPROPERTY(''productversion'') as varchar(20)),1,1) = 8)
) AS [Extent3]) AS [UnionAll1] ON (0 = [UnionAll1].[C1]) AND ([Extent1].[Id] = [UnionAll1].[ParentId])
LEFT OUTER JOIN (SELECT
[UnionAll2].[Id] AS [C1],
cast(1 as bit) AS [C2]
FROM (
SELECT
quotename(tc.CONSTRAINT_SCHEMA) + quotename(tc.CONSTRAINT_NAME) [Id]
, quotename(tc.TABLE_SCHEMA) + quotename(tc.TABLE_NAME) [ParentId]
, tc.CONSTRAINT_NAME [Name]
, tc.CONSTRAINT_TYPE [ConstraintType]
, CAST(CASE tc.IS_DEFERRABLE WHEN ''NO'' THEN 0 ELSE 1 END as bit) [IsDeferrable]
, CAST(CASE tc.INITIALLY_DEFERRED WHEN ''NO'' THEN 0 ELSE 1 END as bit) [IsInitiallyDeferred]
FROM
INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc
WHERE tc.TABLE_NAME IS NOT NULL
) AS [Extent4]
INNER JOIN (SELECT
7 AS [C1],
[Extent5].[ConstraintId] AS [ConstraintId],
[Extent6].[Id] AS [Id]
FROM (
SELECT
quotename(CONSTRAINT_SCHEMA) + quotename(CONSTRAINT_NAME) [ConstraintId]
, quotename(TABLE_SCHEMA) + quotename(TABLE_NAME) + quotename(COLUMN_NAME) [ColumnId]
FROM
INFORMATION_SCHEMA.KEY_COLUMN_USAGE
) AS [Extent5]
INNER JOIN (
SELECT
quotename(c.TABLE_SCHEMA) + quotename(c.TABLE_NAME) + quotename(c.COLUMN_NAME) [Id]
, quotename(c.TABLE_SCHEMA) + quotename(c.TABLE_NAME) [ParentId]
, c.COLUMN_NAME [Name]
, c.ORDINAL_POSITION [Ordinal]
, CAST( CASE c.IS_NULLABLE WHEN ''YES'' THEN 1 WHEN ''NO'' THEN 0 ELSE 0 END as bit) [IsNullable]
, CASE
WHEN c.DATA_TYPE in (''varchar'', ''nvarchar'', ''varbinary'') and
c.CHARACTER_MAXIMUM_LENGTH = -1 THEN
c.DATA_TYPE + ''(max)''
ELSE
c.DATA_TYPE
END
as [TypeName]
, c.CHARACTER_MAXIMUM_LENGTH [MaxLength]
, CAST(c.NUMERIC_PRECISION as integer) [Precision]
, CAST(c.DATETIME_PRECISION as integer)[DateTimePrecision]
, CAST(c.NUMERIC_SCALE as integer) [Scale]
, c.COLLATION_CATALOG [CollationCatalog]
, c.COLLATION_SCHEMA [CollationSchema]
, c.COLLATION_NAME [CollationName]
, c.CHARACTER_SET_CATALOG [CharacterSetCatalog]
, c.CHARACTER_SET_SCHEMA [CharacterSetSchema]
, c.CHARACTER_SET_NAME [CharacterSetName]
, CAST(0 as bit) as [IsMultiSet]
, CAST(columnproperty( object_id(quotename(c.TABLE_SCHEMA) + ''.'' + quotename(c.TABLE_NAME)), c.COLUMN_NAME, ''IsIdentity'' ) as bit) as [IsIdentity]
, CAST(columnproperty( object_id(quotename(c.TABLE_SCHEMA) + ''.'' + quotename(c.TABLE_NAME)), c.COLUMN_NAME, ''IsComputed'' ) | CASE WHEN c.DATA_TYPE = ''timestamp'' THEN 1 ELSE 0 END as bit) as [IsStoreGenerated]
, c.COLUMN_DEFAULT as [Default]
FROM
INFORMATION_SCHEMA.COLUMNS c
INNER JOIN
INFORMATION_SCHEMA.TABLES t ON
c.TABLE_CATALOG = t.TABLE_CATALOG AND
c.TABLE_SCHEMA = t.TABLE_SCHEMA AND
c.TABLE_NAME = t.TABLE_NAME AND
t.TABLE_TYPE = ''BASE TABLE''
) AS [Extent6] ON [Extent6].[Id] = [Extent5].[ColumnId]
UNION ALL
SELECT
11 AS [C1],
[Extent7].[ConstraintId] AS [ConstraintId],
[Extent8].[Id] AS [Id]
FROM (
SELECT
CAST(NULL as nvarchar(1)) [ConstraintId]
, CAST(NULL as nvarchar(max)) [ColumnId]
WHERE 1=2
) AS [Extent7]
INNER JOIN (
SELECT
quotename(c.TABLE_SCHEMA) + quotename(c.TABLE_NAME) + quotename(c.COLUMN_NAME) [Id]
, quotename(c.TABLE_SCHEMA) + quotename(c.TABLE_NAME) [ParentId]
, c.COLUMN_NAME [Name]
, c.ORDINAL_POSITION [Ordinal]
, CAST( CASE c.IS_NULLABLE WHEN ''YES'' THEN 1 WHEN ''NO'' THEN 0 ELSE 0 END as bit) [IsNullable]
, CASE
WHEN c.DATA_TYPE in (''varchar'', ''nvarchar'', ''varbinary'') and
c.CHARACTER_MAXIMUM_LENGTH = -1 THEN
c.DATA_TYPE + ''(max)''
ELSE
c.DATA_TYPE
END
as [TypeName]
, c.CHARACTER_MAXIMUM_LENGTH [MaxLength]
, CAST(c.NUMERIC_PRECISION as integer) [Precision]
, CAST(c.DATETIME_PRECISION as integer) as [DateTimePrecision]
, CAST(c.NUMERIC_SCALE as integer) [Scale]
, c.COLLATION_CATALOG [CollationCatalog]
, c.COLLATION_SCHEMA [CollationSchema]
, c.COLLATION_NAME [CollationName]
, c.CHARACTER_SET_CATALOG [CharacterSetCatalog]
, c.CHARACTER_SET_SCHEMA [CharacterSetSchema]
, c.CHARACTER_SET_NAME [CharacterSetName]
, CAST(0 as bit) as [IsMultiSet]
, CAST(columnproperty( object_id(quotename(c.TABLE_SCHEMA) + ''.'' + quotename(c.TABLE_NAME)), c.COLUMN_NAME, ''IsIdentity'' ) as bit) as [IsIdentity]
, CAST(columnproperty( object_id(quotename(c.TABLE_SCHEMA) + ''.'' + quotename(c.TABLE_NAME)), c.COLUMN_NAME, ''IsComputed'' ) | CASE WHEN c.DATA_TYPE = ''timestamp'' THEN 1 ELSE 0 END as bit) as [IsStoreGenerated]
, c.COLUMN_DEFAULT [Default]
FROM
INFORMATION_SCHEMA.COLUMNS c
INNER JOIN
INFORMATION_SCHEMA.VIEWS v ON
c.TABLE_CATALOG = v.TABLE_CATALOG AND
c.TABLE_SCHEMA = v.TABLE_SCHEMA AND
c.TABLE_NAME = v.TABLE_NAME
WHERE
NOT (v.TABLE_SCHEMA = ''dbo''
AND v.TABLE_NAME in(''syssegments'', ''sysconstraints'')
AND SUBSTRING(CAST(SERVERPROPERTY(''productversion'') as varchar(20)),1,1) = 8)
) AS [Extent8] ON [Extent8].[Id] = [Extent7].[ColumnId]) AS [UnionAll2] ON (7 = [UnionAll2].[C1]) AND ([Extent4].[Id] = [UnionAll2].[ConstraintId])
WHERE [Extent4].[ConstraintType] = N''PRIMARY KEY'' ) AS [Project5] ON [UnionAll1].[Id] = [Project5].[C1]
WHERE NOT ([Extent1].[Name] LIKE @p0)',N'@p0 nvarchar(4000)',@p0=N'__RefactorLog'

Answer

Like user1666620 expected, it was a problem with the cardinality estimation of SQL-Server 2014 or later. For the given query it leads to the problem, that the estimation of query results is interpreted wrong. There are two ways to solve the problem:

  1. Give the the query the following as parameter in the where clause:
    OPTION(QUERYTRACEON 9481)

    usage:
    WHERE NOT ([Extent1].[Name] LIKE @p0) OPTION(QUERYTRACEON 9481)',N'@p0 nvarchar(4000)',@p0=N'__RefactorLog'
  2. Disable the "Legacy Cardinality Estimation" on database.

Database->Properties->Options->Legacy Cardinality Estimation = ON

enter image description here