Delete large number of records

  • Hi all,

    I have the following scenario and looking for some advise:

    SQL database on SQL 2012

    Large Production table 15 Million record

    The table has 3 years of data

    New monthly data is being added every month.

    A New Monthly data is being loaded, checked and finally approved after 6 or 7 iteration before approval.

    Because of this iteration the monthly data set is being added then deleted then added then deleted few times.

    Because the table is big this process takes time, any thoughts on how to make the delete insert process faster.

    Keep in mind I cannot do much because it is a production table and is being access by other users to do other analysis.

    Delete is done based on trx_date which is a year/month combo, like 201508.

    The table has monthly sales by customer aggregated.

    The table structure is:

    CREATE TABLE [dbo].[Sales](

    [batch_key] [int] NOT NULL,

    [Company_key] [int] NOT NULL,

    [customer_key] [char](22) NOT NULL,

    [Trx_Date] [int] NOT NULL,

    [account] [nvarchar](35) NOT NULL,

    [Currency] [char](3) NOT NULL,

    [region] [char](15) NOT NULL,

    [state] [char](15) NOT NULL,

    [location] [char](15) NOT NULL,

    [unit] [char](15) NOT NULL,

    [slsrep] [char](15) NOT NULL,

    [LOB] [char](15) NULL,

    [Sales_MTD] [decimal](38, 2) NULL,

    [Sales_YTD] [decimal](38, 2) NULL

    ) ON [PRIMARY]

    GO

    SET ANSI_PADDING OFF

    GO

    CREATE NONCLUSTERED INDEX [IXslsrep] ON [dbo].[Sales]

    (

    [slsrep] 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

    CREATE NONCLUSTERED INDEX [IXCur] ON [dbo].[Sales]

    (

    [Currency] 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

    CREATE NONCLUSTERED INDEX [IXaccount] ON [dbo].[Sales]

    (

    [account] 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

    CREATE NONCLUSTERED INDEX [IXCompany] ON [dbo].[Sales]

    (

    [Company_key] 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

    CREATE NONCLUSTERED INDEX [IXregion] ON [dbo].[Sales]

    (

    [region] 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

    CREATE NONCLUSTERED INDEX [IXsite] ON [dbo].[Sales]

    (

    [location] 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

    CREATE NONCLUSTERED INDEX [IXbatch] ON [dbo].[Sales]

    (

    [batch_key] 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

    CREATE NONCLUSTERED INDEX [IXTime] ON [dbo].[Sales]

    (

    [Trx_Date] 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

  • oneteabag (9/8/2015)


    Hi all,

    I have the following scenario and looking for some advise:

    SQL database on SQL 2012

    Large Production table 15 Million record

    The table has 3 years of data

    New monthly data is being added every month.

    A New Monthly data is being loaded, checked and finally approved after 6 or 7 iteration before approval.

    Because of this iteration the monthly data set is being added then deleted then added then deleted few times.

    Because the table is big this process takes time, any thoughts on how to make the delete insert process faster.

    Keep in mind I cannot do much because it is a production table and is being access by other users to do other analysis.

    Delete is done based on trx_date which is a year/month combo, like 201508.

    The table has monthly sales by customer aggregated.

    The table structure is:

    CREATE TABLE [dbo].[Sales](

    [batch_key] [int] NOT NULL,

    [Company_key] [int] NOT NULL,

    [customer_key] [char](22) NOT NULL,

    [Trx_Date] [int] NOT NULL,

    [account] [nvarchar](35) NOT NULL,

    [Currency] [char](3) NOT NULL,

    [region] [char](15) NOT NULL,

    [state] [char](15) NOT NULL,

    [location] [char](15) NOT NULL,

    [unit] [char](15) NOT NULL,

    [slsrep] [char](15) NOT NULL,

    [LOB] [char](15) NULL,

    [Sales_MTD] [decimal](38, 2) NULL,

    [Sales_YTD] [decimal](38, 2) NULL

    ) ON [PRIMARY]

    GO

    SET ANSI_PADDING OFF

    GO

    CREATE NONCLUSTERED INDEX [IXslsrep] ON [dbo].[Sales]

    (

    [slsrep] 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

    CREATE NONCLUSTERED INDEX [IXCur] ON [dbo].[Sales]

    (

    [Currency] 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

    CREATE NONCLUSTERED INDEX [IXaccount] ON [dbo].[Sales]

    (

    [account] 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

    CREATE NONCLUSTERED INDEX [IXCompany] ON [dbo].[Sales]

    (

    [Company_key] 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

    CREATE NONCLUSTERED INDEX [IXregion] ON [dbo].[Sales]

    (

    [region] 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

    CREATE NONCLUSTERED INDEX [IXsite] ON [dbo].[Sales]

    (

    [location] 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

    CREATE NONCLUSTERED INDEX [IXbatch] ON [dbo].[Sales]

    (

    [batch_key] 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

    CREATE NONCLUSTERED INDEX [IXTime] ON [dbo].[Sales]

    (

    [Trx_Date] 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

    On average, roughly how many records would exists for an given Trx_Date?

    Have you tried:

    DELETE FROM [dbo].[Sales]

    WHERE [Trx_Date] = 201508;

    If so, how long did it take?



    Alvin Ramard
    Memphis PASS Chapter[/url]

    All my SSC forum answers come with a money back guarantee. If you didn't like the answer then I'll gladly refund what you paid for it.

    For best practices on asking questions, please read the following article: Forum Etiquette: How to post data/code on a forum to get the best help[/url]

  • Any triggers on that table? Specifically any FOR DELETE triggers? How about foreign keys causing cascades on delete?

    -SQLBill

  • 1) No Trigger on the table, no cascade delete.

    2) The delete takes about 7 to 8 Minutes.

    Thanks

  • oneteabag (9/8/2015)


    1) No Trigger on the table, no cascade delete.

    2) The delete takes about 7 to 8 Minutes.

    Thanks

    For how many records?



    Alvin Ramard
    Memphis PASS Chapter[/url]

    All my SSC forum answers come with a money back guarantee. If you didn't like the answer then I'll gladly refund what you paid for it.

    For best practices on asking questions, please read the following article: Forum Etiquette: How to post data/code on a forum to get the best help[/url]

  • There are two main reasons it's taking so long:

    1) no clustered index

    2) too many nonclustered indexes

    My best guess is that Trx_Date should be the clustered index. But we need to look at stats to be sure.

    If you run the attached queries and post the results, I'll give you the index commands to fix it.

    SET DEADLOCK_PRIORITY -8

    IF OBJECT_ID('tempdb.dbo.#index_specs') IS NOT NULL

    DROP TABLE dbo.#index_specs

    CREATE TABLE dbo.#index_specs (

    object_id int NOT NULL,

    index_id int NOT NULL,

    min_compression int NULL,

    max_compression int NULL,

    alloc_mb decimal(9, 1) NOT NULL,

    used_mb decimal(9, 1) NOT NULL,

    size_rank int NULL,

    CONSTRAINT index_specs__CL UNIQUE CLUSTERED ( object_id, index_id )

    )

    DECLARE @list_missing_indexes bit

    DECLARE @table_name_pattern sysname

    DECLARE @order_by smallint --1=table_name; 2=size; -2=size DESC;.

    DECLARE @format_row_count smallint --1=with commas, no decimals; 2/3=with K=1000s,M=1000000s, with 2=0 dec. or 3=1 dec. places;.

    DECLARE @debug smallint

    --NOTE: showing missing indexes can take some time, set to 0 if you don't want to wait.

    SET @list_missing_indexes = 1

    SET @table_name_pattern = 'Sales'

    SET @order_by = 1

    SET @format_row_count = 3

    SET @debug = 99

    --SELECT create_date FROM sys.databases /*WITH (NOLOCK)*/ WHERE name = N'tempdb'

    PRINT 'Started @ ' + CONVERT(varchar(30), GETDATE(), 120)

    DECLARE @is_compression_available bit

    DECLARE @sql varchar(8000)

    IF CAST(SERVERPROPERTY('ProductVersion') AS varchar(30)) LIKE '9%'

    SET @is_compression_available = 0

    ELSE

    SET @is_compression_available = 1

    SET @sql = '

    INSERT INTO #index_specs ( object_id, index_id, ' +

    CASE WHEN @is_compression_available = 0 THEN '' ELSE '

    min_compression, max_compression,' END + '

    alloc_mb, used_mb )

    SELECT

    part.object_id,

    part.index_id,' +

    CASE WHEN @is_compression_available = 0 THEN '' ELSE '

    ISNULL(MIN(part.data_compression), 0) AS min_compression,

    ISNULL(MAX(part.data_compression), 0) AS max_compression,' END + '

    SUM(au.total_pages) / 128.0 AS alloc_mb,

    SUM(au.used_pages) / 128.0 AS used_mb

    FROM sys.partitions part

    INNER JOIN sys.allocation_units au ON

    au.container_id = part.partition_id

    GROUP BY

    part.object_id,

    part.index_id

    '

    IF @debug >= 1

    PRINT @sql

    EXEC(@sql)

    UPDATE ispec

    SET size_rank = ispec_ranking.size_rank

    FROM #index_specs ispec

    INNER JOIN (

    SELECT object_id, ROW_NUMBER() OVER(ORDER BY alloc_mb DESC) AS size_rank

    FROM (

    SELECT object_id, SUM(alloc_mb) AS alloc_mb

    FROM #index_specs

    GROUP BY object_id

    ) AS ispec_allocs

    ) AS ispec_ranking ON

    ispec_ranking.object_id = ispec.object_id

    IF @list_missing_indexes = 1

    BEGIN

    SELECT

    DB_NAME(mid.database_id) AS Db_Name,

    CONVERT(varchar(10), GETDATE(), 120) AS capture_date,

    ispec.size_rank, ispec.alloc_mb,

    CASE WHEN @format_row_count = 1 THEN REPLACE(CONVERT(varchar(20), CAST(dps.row_count AS money), 1), '.00', '')

    WHEN @format_row_count = 2 THEN CAST(CAST(dps.row_count * 1.0 / CASE ca1.row_count_suffix

    WHEN 'M' THEN 1000000 WHEN 'K' THEN 1000 ELSE 1 END AS int) AS varchar(20)) + ca1.row_count_suffix

    WHEN @format_row_count = 3 THEN CAST(CAST(dps.row_count * 1.0 / CASE ca1.row_count_suffix

    WHEN 'M' THEN 1000000 WHEN 'K' THEN 1000 ELSE 1 END AS decimal(14, 1)) AS varchar(20)) + ca1.row_count_suffix

    ELSE CAST(dps.row_count AS varchar(20)) END AS row_count,

    OBJECT_SCHEMA_NAME(mid.object_id /*, mid.database_id*/) + '.' + OBJECT_NAME(mid.object_id /*, mid.database_id*/) AS Table_Name,

    mid.equality_columns, mid.inequality_columns, mid.included_columns,

    user_seeks, user_scans, cj1.max_days_active, unique_compiles,

    last_user_seek, last_user_scan, avg_total_user_cost, avg_user_impact,

    system_seeks, system_scans, last_system_seek, last_system_scan, avg_total_system_cost, avg_system_impact,

    mid.statement, mid.object_id, mid.index_handle

    FROM sys.dm_db_missing_index_details mid /*WITH (NOLOCK)*/

    CROSS JOIN (

    SELECT DATEDIFF(DAY, create_date, GETDATE()) AS max_days_active FROM sys.databases /*WITH (NOLOCK)*/ WHERE name = 'tempdb'

    ) AS cj1

    LEFT OUTER JOIN sys.dm_db_missing_index_groups mig /*WITH (NOLOCK)*/ ON

    mig.index_handle = mid.index_handle

    LEFT OUTER JOIN sys.dm_db_missing_index_group_stats migs /*WITH (NOLOCK)*/ ON

    migs.group_handle = mig.index_group_handle

    LEFT OUTER JOIN sys.dm_db_partition_stats dps /*WITH (NOLOCK)*/ ON

    dps.object_id = mid.object_id AND

    dps.index_id IN (0, 1)

    CROSS APPLY (

    SELECT CASE WHEN dps.row_count >= 1000000 THEN 'M' WHEN dps.row_count >= 1000 THEN 'K' ELSE '' END AS row_count_suffix

    ) AS ca1

    OUTER APPLY (

    SELECT ispec.alloc_mb, ispec.size_rank

    FROM dbo.#index_specs ispec

    WHERE

    ispec.object_id = mid.object_id AND

    ispec.index_id IN (0, 1)

    ) AS ispec

    --order by

    --DB_NAME, Table_Name, equality_columns

    WHERE

    1 = 1

    AND mid.database_id = DB_ID()

    AND OBJECT_NAME(mid.object_id) LIKE @table_name_pattern

    AND OBJECT_NAME(mid.object_id) NOT LIKE 'tmp%'

    ORDER BY

    --avg_total_user_cost * (user_seeks + user_scans) DESC,

    Db_Name,

    CASE WHEN @order_by IN (-2, 2) THEN ispec.size_rank * -SIGN(@order_by) ELSE 0 END,

    Table_Name,

    equality_columns, inequality_columns,

    user_seeks DESC

    END --IF

    PRINT 'Index Usage Stats @ ' + CONVERT(varchar(30), GETDATE(), 120)

    -- list index usage stats (seeks, scans, etc.)

    SELECT

    DB_NAME() AS db_name,

    ispec.size_rank, ispec.alloc_mb - ispec.used_mb AS [*un*used_mb], ispec.alloc_mb,

    SUBSTRING('NY', CAST(i.is_primary_key AS int) + CAST(i.is_unique_constraint AS int) + 1, 1) +

    CASE WHEN i.is_unique = CAST(i.is_primary_key AS int) + CAST(i.is_unique_constraint AS int) THEN ''

    ELSE '.' + SUBSTRING('NY', CAST(i.is_unique AS int) + 1, 1) END AS [uniq?],

    REPLACE(i.name, ca1.table_name, '~') AS index_name,

    OBJECT_SCHEMA_NAME(i.object_id /*, DB_ID()*/) + '.' + ca1.table_name AS Table_Name,

    CASE WHEN @format_row_count = 1 THEN REPLACE(CONVERT(varchar(20), CAST(dps.row_count AS money), 1), '.00', '')

    WHEN @format_row_count = 2 THEN CAST(CAST(dps.row_count * 1.0 / CASE ca1.row_count_suffix

    WHEN 'M' THEN 1000000 WHEN 'K' THEN 1000 ELSE 1 END AS int) AS varchar(20)) + ca1.row_count_suffix

    WHEN @format_row_count = 3 THEN CAST(CAST(dps.row_count * 1.0 / CASE ca1.row_count_suffix

    WHEN 'M' THEN 1000000 WHEN 'K' THEN 1000 ELSE 1 END AS decimal(14, 1)) AS varchar(20)) + ca1.row_count_suffix

    ELSE CAST(dps.row_count AS varchar(20)) END AS row_count,

    i.index_id,

    SUBSTRING(key_cols, 3, 8000) AS key_cols, SUBSTRING(nonkey_cols, 3, 8000) AS nonkey_cols,

    ius.user_seeks, ius.user_scans, --ius.user_seeks + ius.user_scans AS total_reads,

    ius.user_lookups, ius.user_updates,

    DATEDIFF(DAY, STATS_DATE ( i.object_id , i.index_id ), GETDATE()) AS stats_days_old,

    ius.last_user_seek, ius.last_user_scan, ius.last_user_lookup, ius.last_user_update,

    fk.Reference_Count AS fk_ref_count,

    DATEDIFF(DAY, CASE

    WHEN o.create_date > cj1.sql_startup_date AND o.create_date > o.modify_date THEN o.create_date

    WHEN o.modify_date > cj1.sql_startup_date AND o.modify_date > o.create_date THEN o.modify_date

    ELSE cj1.sql_startup_date END, GETDATE()) AS max_days_active,

    i.fill_factor,

    ius2.row_num,

    CASE

    WHEN ispec.max_compression IS NULL THEN '(Not applicable)'

    WHEN ispec.max_compression = 2 THEN 'Page'

    WHEN ispec.max_compression = 1 THEN 'Row'

    WHEN ispec.max_compression = 0 THEN ''

    ELSE '(Unknown)' END AS max_compression,

    FILEGROUP_NAME(i.data_space_id) AS filegroup_name,

    ius.system_seeks, ius.system_scans, ius.system_lookups, ius.system_updates,

    ius.last_system_seek, ius.last_system_scan, ius.last_system_lookup, ius.last_system_update,

    GETDATE() AS capture_date

    FROM sys.indexes i /*WITH (NOLOCK)*/

    INNER JOIN sys.objects o /*WITH (NOLOCK)*/ ON

    o.object_id = i.object_id

    CROSS JOIN (

    SELECT create_date AS sql_startup_date FROM sys.databases /*WITH (NOLOCK)*/ WHERE name = 'tempdb'

    ) AS cj1

    LEFT OUTER JOIN dbo.#index_specs ispec ON

    ispec.object_id = i.object_id AND

    ispec.index_id = i.index_id

    OUTER APPLY (

    SELECT

    ', ' + COL_NAME(ic.object_id, ic.column_id)

    FROM sys.index_columns ic /*WITH (NOLOCK)*/

    WHERE

    ic.key_ordinal > 0 AND

    ic.object_id = i.object_id AND

    ic.index_id = i.index_id

    ORDER BY

    ic.key_ordinal

    FOR XML PATH('')

    ) AS key_cols (key_cols)

    OUTER APPLY (

    SELECT

    ', ' + COL_NAME(ic.object_id, ic.column_id)

    FROM sys.index_columns ic /*WITH (NOLOCK)*/

    WHERE

    ic.key_ordinal = 0 AND

    ic.object_id = i.object_id AND

    ic.index_id = i.index_id

    ORDER BY

    COL_NAME(ic.object_id, ic.column_id)

    FOR XML PATH('')

    ) AS nonkey_cols (nonkey_cols)

    LEFT OUTER JOIN sys.dm_db_partition_stats dps /*WITH (NOLOCK)*/ ON

    dps.object_id = i.object_id AND

    dps.index_id = i.index_id

    LEFT OUTER JOIN sys.dm_db_index_usage_stats ius /*WITH (NOLOCK)*/ ON

    ius.database_id = DB_ID() AND

    ius.object_id = i.object_id AND

    ius.index_id = i.index_id

    LEFT OUTER JOIN (

    SELECT

    database_id, object_id, MAX(user_scans) AS user_scans,

    ROW_NUMBER() OVER (ORDER BY MAX(user_scans) DESC) AS row_num --user_scans|user_seeks+user_scans

    FROM sys.dm_db_index_usage_stats /*WITH (NOLOCK)*/

    WHERE

    database_id = DB_ID()

    --AND index_id > 0

    GROUP BY

    database_id, object_id

    ) AS ius2 ON

    ius2.database_id = DB_ID() AND

    ius2.object_id = i.object_id

    LEFT OUTER JOIN (

    SELECT

    referenced_object_id, COUNT(*) AS Reference_Count

    FROM sys.foreign_keys /*WITH (NOLOCK)*/

    WHERE

    is_disabled = 0

    GROUP BY

    referenced_object_id

    ) AS fk ON

    fk.referenced_object_id = i.object_id

    OUTER APPLY (

    SELECT OBJECT_NAME(i.object_id/*, DB_ID()*/) AS table_name,

    CASE WHEN dps.row_count >= 1000000 THEN 'M' WHEN dps.row_count >= 1000 THEN 'K' ELSE '' END AS row_count_suffix

    ) AS ca1

    WHERE

    --EXISTS(SELECT 1 FROM sys.indexes i2 /*WITH (NOLOCK)*/ WHERE i2.object_id = i.object_id AND i2.index_id = 0) AND --$T

    i.object_id > 100 AND

    i.is_hypothetical = 0 AND

    i.type IN (0, 1, 2) AND

    o.type NOT IN ( 'IF', 'IT', 'TF', 'TT' ) AND

    (

    o.name LIKE @table_name_pattern AND

    o.name NOT LIKE 'dtprop%' AND

    o.name NOT LIKE 'filestream[_]' AND

    o.name NOT LIKE 'MSpeer%' AND

    o.name NOT LIKE 'MSpub%' --AND

    --o.name NOT LIKE 'queue[_]%' AND

    --o.name NOT LIKE 'sys%' --AND

    --o.name NOT LIKE 'tmp%'

    )

    ORDER BY

    db_name,

    --ius.user_seeks - ius.user_scans,

    CASE WHEN @order_by IN (-2, 2) THEN ispec.size_rank * -SIGN(@order_by) ELSE 0 END,

    --ius.user_scans DESC,

    --ius2.row_num, --user_scans&|user_seeks

    table_name,

    -- list clustered index first, if any, then other index(es)

    CASE WHEN i.index_id IN (0, 1) THEN 1 ELSE 2 END,

    key_cols

    PRINT 'Ended @ ' + CONVERT(varchar(30), GETDATE(), 120)

    SET DEADLOCK_PRIORITY NORMAL

    SQL DBA,SQL Server MVP(07, 08, 09) "It's a dog-eat-dog world, and I'm wearing Milk-Bone underwear." "Norm", on "Cheers". Also from "Cheers", from "Carla": "You need to know 3 things about Tortelli men: Tortelli men draw women like flies; Tortelli men treat women like flies; Tortelli men's brains are in their flies".

  • 150K

  • I will try that Scott shortly.

    However is there a faster way to put this monthly 201508 on a partition and swap it every time we need to refresh it.?

    Thanks

    Sam

  • ScottPletcher (9/8/2015)


    There are two main reasons it's taking so long:

    1) no clustered index

    2) too many nonclustered indexes

    ......

    Ooops! Missed the lack of clustered index.



    Alvin Ramard
    Memphis PASS Chapter[/url]

    All my SSC forum answers come with a money back guarantee. If you didn't like the answer then I'll gladly refund what you paid for it.

    For best practices on asking questions, please read the following article: Forum Etiquette: How to post data/code on a forum to get the best help[/url]

  • You could partition the table, but it's likely overkill in this situation. All you probably need is the best clustered index and only the nonclustered index(es) you actually need, i.e., that SQL will actually gainfully use.

    SQL DBA,SQL Server MVP(07, 08, 09) "It's a dog-eat-dog world, and I'm wearing Milk-Bone underwear." "Norm", on "Cheers". Also from "Cheers", from "Carla": "You need to know 3 things about Tortelli men: Tortelli men draw women like flies; Tortelli men treat women like flies; Tortelli men's brains are in their flies".

  • If you are using the Enterprise Edition of SQL Server, and are maintaining a 3 year history of data, 1 month rolls in and one month rolls out; then partitioning my be a viable alternative. You still need to have a clustered index on the partitioning column for it to work.

  • oneteabag (9/8/2015)


    [font="Arial Black"]A New Monthly data is being loaded, checked and finally approved after 6 or 7 iteration before approval.

    [/font]Because of this iteration the monthly data set is being added then deleted then added then deleted few times.

    Because the table is big this process takes time, any thoughts on how to make the delete insert process faster.

    Keep in mind I cannot do much because it is a production table and is being access by other users to do other analysis.

    That's actually [font="Arial Black"]THE [/font]problem. Why on this good Earth would non-approved data ever be allowed into a production table? Such approval should be done in a staging table and in a non-production environment.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • Good Point Jeff.

    Reason is the process is happening so fast within couple of hours and with every iteration actual production reports are executed and checked until an 'ok' is given.

    In a perfect world this should be done on Staging approved and moved to Prod, as I said this was not done because every thing need to be flipped nearly real time.

    Thanks

  • oneteabag (9/8/2015)


    Good Point Jeff.

    Reason is the process is happening so fast within couple of hours and with every iteration actual production reports are executed and checked until an 'ok' is given.

    In a perfect world this should be done on Staging approved and moved to Prod, as I said this was not done because every thing need to be flipped nearly real time.

    Thanks

    Do they do this same fire drill every month?

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • Yes every month.

    Thanks

Viewing 15 posts - 1 through 15 (of 25 total)

You must be logged in to reply to this topic. Login to reply