sjh37 / EntityFramework-Reverse-POCO-Code-First-Generator

EntityFramework Reverse POCO Code First Generator - Beautifully generated code that is fully customisable. This generator creates code as if you reverse engineered a database and lovingly created the code by hand. It is free to academics (you need a .edu or a .ac email address), not free for commercial use. Obtain your licence from
https://www.reversepoco.co.uk/
Other
709 stars 227 forks source link

Slow running Database.tt generation query #262

Closed tranceporter closed 7 years ago

tranceporter commented 7 years ago

We updated our SQL server to "Microsoft SQL Server 2016 (SP1-CU2) (KB4013106) - 13.0.4422.0 (X64) Mar 6 2017 14:18:16 Copyright (c) Microsoft Corporation Developer Edition (64-bit) on Windows Server 2012 R2 Datacenter 6.3 (Build 9600: ) (Hypervisor)" some time ago. After this, if we save a Database.tt file in VS2015, the SQL query just times out. However, if we run the same query on an environment that has not been upgraded to SQL server 2016, it runs within 15-30 secs. We are using reverse poco generator v2.5.0 and EF6.

EDIT: In the attached query, if we change the LEFT OUTER JOIN to LEFT OUTER MERGE JOIN, it runs in 4 seconds! Is there something that has changed in SQL server 2016 that's causing this issue?

Query is pasted below. Any thoughts please?

faulty sql query.zip

sjh37 commented 7 years ago

Thanks all.

Final SQL is as follows:

SET NOCOUNT ON;
IF OBJECT_ID('tempdb..#Columns')     IS NOT NULL DROP TABLE #Columns;
IF OBJECT_ID('tempdb..#PrimaryKeys') IS NOT NULL DROP TABLE #PrimaryKeys;
IF OBJECT_ID('tempdb..#ForeignKeys') IS NOT NULL DROP TABLE #ForeignKeys;

SELECT  C.TABLE_SCHEMA,
        C.TABLE_NAME,
        C.COLUMN_NAME,
        C.ORDINAL_POSITION,
        C.COLUMN_DEFAULT,
        C.IS_NULLABLE,
        C.DATA_TYPE,
        C.CHARACTER_MAXIMUM_LENGTH,
        C.NUMERIC_PRECISION,
        C.NUMERIC_SCALE,
        C.DATETIME_PRECISION
INTO    #Columns
FROM    INFORMATION_SCHEMA.COLUMNS C
WHERE   C.TABLE_NAME NOT IN ('EdmMetadata', '__MigrationHistory')
        AND C.TABLE_NAME NOT LIKE 'sysdiagram%';

CREATE NONCLUSTERED INDEX IX_EfPoco_Columns
ON dbo.#Columns (TABLE_NAME)
INCLUDE (TABLE_SCHEMA,COLUMN_NAME,ORDINAL_POSITION,COLUMN_DEFAULT,IS_NULLABLE,DATA_TYPE,CHARACTER_MAXIMUM_LENGTH,NUMERIC_PRECISION,NUMERIC_SCALE,DATETIME_PRECISION);

SELECT  u.TABLE_SCHEMA,
        u.TABLE_NAME,
        u.COLUMN_NAME,
        u.ORDINAL_POSITION
INTO    #PrimaryKeys
FROM    INFORMATION_SCHEMA.KEY_COLUMN_USAGE u
        INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc
            ON u.TABLE_SCHEMA COLLATE DATABASE_DEFAULT = tc.CONSTRAINT_SCHEMA COLLATE DATABASE_DEFAULT
               AND u.TABLE_NAME = tc.TABLE_NAME
               AND u.CONSTRAINT_NAME = tc.CONSTRAINT_NAME
WHERE   CONSTRAINT_TYPE = 'PRIMARY KEY';

SELECT DISTINCT
        u.TABLE_SCHEMA,
        u.TABLE_NAME,
        u.COLUMN_NAME
INTO    #ForeignKeys
FROM    INFORMATION_SCHEMA.KEY_COLUMN_USAGE u
        INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc
            ON u.TABLE_SCHEMA COLLATE DATABASE_DEFAULT = tc.CONSTRAINT_SCHEMA COLLATE DATABASE_DEFAULT
               AND u.TABLE_NAME = tc.TABLE_NAME
               AND u.CONSTRAINT_NAME = tc.CONSTRAINT_NAME
WHERE   CONSTRAINT_TYPE = 'FOREIGN KEY';

SELECT  c.TABLE_SCHEMA AS SchemaName,
        c.TABLE_NAME AS TableName,
        t.TABLE_TYPE AS TableType,
        c.ORDINAL_POSITION AS Ordinal,
        c.COLUMN_NAME AS ColumnName,
        CAST(CASE WHEN IS_NULLABLE = 'YES' THEN 1
                  ELSE 0
             END AS BIT) AS IsNullable,
        DATA_TYPE AS TypeName,
        ISNULL(CHARACTER_MAXIMUM_LENGTH, 0) AS MaxLength,
        CAST(ISNULL(NUMERIC_PRECISION, 0) AS INT) AS Precision,
        ISNULL(COLUMN_DEFAULT, '') AS [Default],
        CAST(ISNULL(DATETIME_PRECISION, 0) AS INT) AS DateTimePrecision,
        ISNULL(NUMERIC_SCALE, 0) AS Scale,
        CAST(COLUMNPROPERTY(OBJECT_ID(QUOTENAME(c.TABLE_SCHEMA) + '.' + QUOTENAME(c.TABLE_NAME)), c.COLUMN_NAME, 'IsIdentity') AS BIT) AS IsIdentity,
        CAST(CASE WHEN COLUMNPROPERTY(OBJECT_ID(QUOTENAME(c.TABLE_SCHEMA) + '.' + QUOTENAME(c.TABLE_NAME)), c.COLUMN_NAME, 'IsIdentity') = 1 THEN 1
                  WHEN COLUMNPROPERTY(OBJECT_ID(QUOTENAME(c.TABLE_SCHEMA) + '.' + QUOTENAME(c.TABLE_NAME)), c.COLUMN_NAME, 'IsComputed') = 1 THEN 1
                  WHEN DATA_TYPE = 'TIMESTAMP' THEN 1
                  WHEN DATA_TYPE = 'UNIQUEIDENTIFIER'
                       AND LOWER(ISNULL(COLUMN_DEFAULT, '')) LIKE '%newsequentialid%' THEN 1
                  ELSE 0
             END AS BIT) AS IsStoreGenerated,
        CAST(CASE WHEN pk.ORDINAL_POSITION IS NULL THEN 0
                  ELSE 1
             END AS BIT) AS PrimaryKey,
        ISNULL(pk.ORDINAL_POSITION, 0) PrimaryKeyOrdinal,
        CAST(CASE WHEN fk.COLUMN_NAME IS NULL THEN 0
                  ELSE 1
             END AS BIT) AS IsForeignKey
FROM    #Columns c
        LEFT OUTER JOIN #PrimaryKeys pk
            ON c.TABLE_SCHEMA = pk.TABLE_SCHEMA
               AND c.TABLE_NAME = pk.TABLE_NAME
               AND c.COLUMN_NAME = pk.COLUMN_NAME
        LEFT OUTER JOIN #ForeignKeys fk
            ON c.TABLE_SCHEMA = fk.TABLE_SCHEMA
               AND c.TABLE_NAME = fk.TABLE_NAME
               AND c.COLUMN_NAME = fk.COLUMN_NAME
        INNER JOIN INFORMATION_SCHEMA.TABLES t
            ON c.TABLE_SCHEMA COLLATE DATABASE_DEFAULT = t.TABLE_SCHEMA COLLATE DATABASE_DEFAULT
               AND c.TABLE_NAME COLLATE DATABASE_DEFAULT = t.TABLE_NAME COLLATE DATABASE_DEFAULT
WHERE   c.TABLE_NAME NOT IN ('EdmMetadata', '__MigrationHistory')
        AND c.TABLE_NAME NOT LIKE 'sysdiagram%';