Lesson Learned #138: Transferring data between two tables is taking too much resources

Published 09-30-2020 05:22 PM 920 Views

Today, I worked on a service request that our customer has an internal process that every night they transferred data from table (iot_table1) to another table (iot_table2) based on several filters. Despite that the number of rows of the source table is increasing every day, this process is taking all the transaction log resource due to amount of data that this process is transferring. 

 

In this type of situation, our best recomendation is to use Business Critical o Premium because the IO capacity is greater if you are using General Purpose or Standard. But, our customer, wants to find an alternative to stay in the Standard/General Purpose without moving to Premium/Business Critical in order to reduce the cost. 

 

Let's assume that our customer has two tables: IOT_Table1 (source) and IOT_Table2 (destination).

 

 

 

CREATE TABLE [dbo].[iot_table1](
	[id] [int] NOT NULL,
	[text] [nchar](10) NULL,
	[Date] [datetime] NULL,
 CONSTRAINT [PK_iot_table1] PRIMARY KEY CLUSTERED 
(
	[id] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[iot_table2](
	[id] [int] NOT NULL,
	[text] [nchar](10) NULL,
 CONSTRAINT [PK_iot_table2] PRIMARY KEY CLUSTERED 
(
	[id] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO

 

 

 

We suggested different workarounds to prevent the execution of this process, for example, using an incremental process using Azure Data Factory or the following alternatives using SQL Server Engine:

 

  • Alternative 1) Create a trigger that for every row that you are inserting in the table iot_table1 will be transferred to iot_table2. I’m sharing with you an example about it:

 

 

 

CREATE TRIGGER [dbo].[inserted]
   ON [dbo].[iot_table1]
   AFTER INSERT
AS 
BEGIN
    SET NOCOUNT ON;
    INSERT INTO IOT_table2(ID,[TEXT]) SELECT ID,[TEXT] from inserted
END

 

 

 

  • Alternative 2) Reduce the amount of numbers of rows to be transferred, for example, creating a table per day. 

 

 

 

CREATE TRIGGER [dbo].[inserted]
   ON [dbo].[iot_table1]
   AFTER INSERT
AS 
BEGIN
       DECLARE @DAY AS VARCHAR(2)
       DECLARE @MONTH AS VARCHAR(2)
       DECLARE @YEAR AS VARCHAR(4)
       SET NOCOUNT ON;
       SET @DAY = CONVERT(VARCHAR(2),DAY(GETDATE()))
       SET @MONTH = CONVERT(VARCHAR(2),MONTH(GETDATE()))
       SET @YEAR = CONVERT(VARCHAR(4),YEAR(GETDATE()))
       IF @MONTH=9 AND @DAY =25 AND @YEAR=2020
       INSERT INTO IOT_table2_2020_09_25(ID,[TEXT]) SELECT ID,[TEXT] from inserted
    IF @MONTH=9 AND @DAY =26 AND @YEAR=2020
       INSERT INTO IOT_table2_2020_09_26(ID,[TEXT]) SELECT ID,[TEXT] from inserted
    IF @MONTH=9 AND @DAY =27 AND @YEAR=2020
       INSERT INTO IOT_table2_2020_09_27(ID,[TEXT]) SELECT ID,[TEXT] from inserted         
    IF @MONTH=9 AND @DAY =28 AND @YEAR=2020
       INSERT INTO IOT_table2_2020_09_28(ID,[TEXT]) SELECT ID,[TEXT] from inserted         
    IF @MONTH=9 AND @DAY =29 AND @YEAR=2020
       INSERT INTO IOT_table2_2020_09_29(ID,[TEXT]) SELECT ID,[TEXT] from inserted         
END

 

 

 

    • You could create an indexed view that the definition, as example, could be:

 

 

 

CREATE OR ALTER VIEW Data_Per_Day_29_09_2020
WITH SCHEMABINDING
AS
SELECT ID, [TEXT] from dbo.iot_table1 where DAY([DATE])=29 and MONTH([DATE])=9 AND YEAR([DATE])=2020

CREATE UNIQUE CLUSTERED Index Data_Per_Day_29_09_2020_X1 ON Data_Per_Day_29_09_2020(ID)

 

 

 

 

    • When you have an indexed view the data will be automatically saved as materialized data, so, in every row that you added in the table depending on the value of the field DATE you are going to have a materialized view with data. If you run the query using this view SELECT * FROM Data_Per_Day_29_09_2020 WITH (NOEXPAND) the data that you are going to have is the materialized data and will be not retrieved from the table. If you use SELECT * FROM Data_Per_Day_29_09_2020 the data will be retrieved from the table.

 

Enjoy!!

%3CLINGO-SUB%20id%3D%22lingo-sub-1726198%22%20slang%3D%22en-US%22%3ELesson%20Learned%20%23138%3A%20Transferring%20data%20between%20two%20tables%20is%20taking%20too%20much%20resources%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-1726198%22%20slang%3D%22en-US%22%3E%3CP%3EToday%2C%20I%20worked%20on%20a%20service%20request%20that%20our%20customer%20has%20an%20internal%20process%20that%20every%20night%20they%20transferred%20data%20from%20table%20(iot_table1)%20to%20another%20table%20(iot_table2)%20based%20on%20several%20filters.%20Despite%20that%20the%20number%20of%20rows%20of%20the%20source%20table%20is%20increasing%20every%20day%2C%20this%20process%20is%20taking%20all%20the%20transaction%20log%20resource%20due%20to%20amount%20of%20data%20that%20this%20process%20is%20transferring.%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3EIn%20this%20type%20of%20situation%2C%20our%20best%20recomendation%20is%20to%20use%20Business%20Critical%20o%20Premium%20because%20the%20IO%20capacity%20is%20greater%20if%20you%20are%20using%20General%20Purpose%20or%20Standard.%20But%2C%20our%20customer%2C%20wants%20to%20find%20an%20alternative%20to%20stay%20in%20the%20Standard%2FGeneral%20Purpose%20without%20moving%20to%20Premium%2FBusiness%20Critical%20in%20order%20to%20reduce%20the%20cost.%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3ELet's%20assume%20that%20our%20customer%20has%20two%20tables%3A%20IOT_Table1%20(source)%20and%20IOT_Table2%20(destination).%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CPRE%20class%3D%22lia-code-sample%20language-sql%22%3E%3CCODE%3ECREATE%20TABLE%20%5Bdbo%5D.%5Biot_table1%5D(%0A%20%5Bid%5D%20%5Bint%5D%20NOT%20NULL%2C%0A%20%5Btext%5D%20%5Bnchar%5D(10)%20NULL%2C%0A%20%5BDate%5D%20%5Bdatetime%5D%20NULL%2C%0A%20CONSTRAINT%20%5BPK_iot_table1%5D%20PRIMARY%20KEY%20CLUSTERED%20%0A(%0A%20%5Bid%5D%20ASC%0A)WITH%20(STATISTICS_NORECOMPUTE%20%3D%20OFF%2C%20IGNORE_DUP_KEY%20%3D%20OFF)%20ON%20%5BPRIMARY%5D%0A)%20ON%20%5BPRIMARY%5D%0AGO%0ACREATE%20TABLE%20%5Bdbo%5D.%5Biot_table2%5D(%0A%20%5Bid%5D%20%5Bint%5D%20NOT%20NULL%2C%0A%20%5Btext%5D%20%5Bnchar%5D(10)%20NULL%2C%0A%20CONSTRAINT%20%5BPK_iot_table2%5D%20PRIMARY%20KEY%20CLUSTERED%20%0A(%0A%20%5Bid%5D%20ASC%0A)WITH%20(STATISTICS_NORECOMPUTE%20%3D%20OFF%2C%20IGNORE_DUP_KEY%20%3D%20OFF)%20ON%20%5BPRIMARY%5D%0A)%20ON%20%5BPRIMARY%5D%0AGO%0A%0A%3C%2FCODE%3E%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3EWe%20suggested%20different%20workarounds%20to%20prevent%20the%20execution%20of%20this%20process%2C%20for%20example%2C%20using%20an%20incremental%20process%20using%20Azure%20Data%20Factory%20or%20the%20following%20alternatives%20using%20SQL%20Server%20Engine%3A%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CUL%3E%0A%3CLI%3E%3CSTRONG%3EAlternative%201)%20Create%20a%20trigger%20that%20for%20every%20row%20that%20you%20are%20inserting%20in%20the%20table%20iot_table1%20will%20be%20transferred%20to%20iot_table2.%20I%E2%80%99m%20sharing%20with%20you%20an%20example%20about%20it%3A%3C%2FSTRONG%3E%3C%2FLI%3E%0A%3C%2FUL%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CPRE%20class%3D%22lia-code-sample%20language-sql%22%3E%3CCODE%3ECREATE%20TRIGGER%20%5Bdbo%5D.%5Binserted%5D%0A%20%20%20ON%20%5Bdbo%5D.%5Biot_table1%5D%0A%20%20%20AFTER%20INSERT%0AAS%20%0ABEGIN%0A%20%20%20%20SET%20NOCOUNT%20ON%3B%0A%20%20%20%20INSERT%20INTO%20IOT_table2(ID%2C%5BTEXT%5D)%20SELECT%20ID%2C%5BTEXT%5D%20from%20inserted%0AEND%0A%3C%2FCODE%3E%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CUL%3E%0A%3CLI%3E%3CSTRONG%3EAlternative%202)%20Reduce%20the%20amount%20of%20numbers%20of%20rows%20to%20be%20transferred%2C%20for%20example%2C%20creating%20a%20table%20per%20day.%26nbsp%3B%3C%2FSTRONG%3E%3C%2FLI%3E%0A%3C%2FUL%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CPRE%20class%3D%22lia-code-sample%20language-sql%22%3E%3CCODE%3ECREATE%20TRIGGER%20%5Bdbo%5D.%5Binserted%5D%0A%20%20%20ON%20%5Bdbo%5D.%5Biot_table1%5D%0A%20%20%20AFTER%20INSERT%0AAS%20%0ABEGIN%0A%20%20%20%20%20%20%20DECLARE%20%40DAY%20AS%20VARCHAR(2)%0A%20%20%20%20%20%20%20DECLARE%20%40MONTH%20AS%20VARCHAR(2)%0A%20%20%20%20%20%20%20DECLARE%20%40YEAR%20AS%20VARCHAR(4)%0A%20%20%20%20%20%20%20SET%20NOCOUNT%20ON%3B%0A%20%20%20%20%20%20%20SET%20%40DAY%20%3D%20CONVERT(VARCHAR(2)%2CDAY(GETDATE()))%0A%20%20%20%20%20%20%20SET%20%40MONTH%20%3D%20CONVERT(VARCHAR(2)%2CMONTH(GETDATE()))%0A%20%20%20%20%20%20%20SET%20%40YEAR%20%3D%20CONVERT(VARCHAR(4)%2CYEAR(GETDATE()))%0A%20%20%20%20%20%20%20IF%20%40MONTH%3D9%20AND%20%40DAY%20%3D25%20AND%20%40YEAR%3D2020%0A%20%20%20%20%20%20%20INSERT%20INTO%20IOT_table2_2020_09_25(ID%2C%5BTEXT%5D)%20SELECT%20ID%2C%5BTEXT%5D%20from%20inserted%0A%20%20%20%20IF%20%40MONTH%3D9%20AND%20%40DAY%20%3D26%20AND%20%40YEAR%3D2020%0A%20%20%20%20%20%20%20INSERT%20INTO%20IOT_table2_2020_09_26(ID%2C%5BTEXT%5D)%20SELECT%20ID%2C%5BTEXT%5D%20from%20inserted%0A%20%20%20%20IF%20%40MONTH%3D9%20AND%20%40DAY%20%3D27%20AND%20%40YEAR%3D2020%0A%20%20%20%20%20%20%20INSERT%20INTO%20IOT_table2_2020_09_27(ID%2C%5BTEXT%5D)%20SELECT%20ID%2C%5BTEXT%5D%20from%20inserted%20%20%20%20%20%20%20%20%20%0A%20%20%20%20IF%20%40MONTH%3D9%20AND%20%40DAY%20%3D28%20AND%20%40YEAR%3D2020%0A%20%20%20%20%20%20%20INSERT%20INTO%20IOT_table2_2020_09_28(ID%2C%5BTEXT%5D)%20SELECT%20ID%2C%5BTEXT%5D%20from%20inserted%20%20%20%20%20%20%20%20%20%0A%20%20%20%20IF%20%40MONTH%3D9%20AND%20%40DAY%20%3D29%20AND%20%40YEAR%3D2020%0A%20%20%20%20%20%20%20INSERT%20INTO%20IOT_table2_2020_09_29(ID%2C%5BTEXT%5D)%20SELECT%20ID%2C%5BTEXT%5D%20from%20inserted%20%20%20%20%20%20%20%20%20%0AEND%0A%3C%2FCODE%3E%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CUL%3E%0A%3CLI%3E%3CSTRONG%3EAlternative%203)%20Using%20Indexed%20views%20but%20it%20is%20depending%20on%20the%20definition%20of%20this%20table%2C%20because%20we%20have%20some%20limitations%2C%20for%20example%3A%20-%20%3C%2FSTRONG%3E%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fsql%2Frelational-databases%2Fviews%2Fcreate-indexed-views%3Fview%3Dsql-server-ver15%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3Ehttps%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fsql%2Frelational-databases%2Fviews%2Fcreate-indexed-views%3Fview%3Dsql-server-ver15%3C%2FA%3E%3C%2FLI%3E%0A%3C%2FUL%3E%0A%3CUL%3E%0A%3CUL%3E%0A%3CLI%3EYou%20could%20create%20an%20indexed%20view%20that%20the%20definition%2C%20as%20example%2C%20could%20be%3A%3C%2FLI%3E%0A%3C%2FUL%3E%0A%3C%2FUL%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CPRE%20class%3D%22lia-code-sample%20language-sql%22%3E%3CCODE%3ECREATE%20OR%20ALTER%20VIEW%20Data_Per_Day_29_09_2020%0AWITH%20SCHEMABINDING%0AAS%0ASELECT%20ID%2C%20%5BTEXT%5D%20from%20dbo.iot_table1%20where%20DAY(%5BDATE%5D)%3D29%20and%20MONTH(%5BDATE%5D)%3D9%20AND%20YEAR(%5BDATE%5D)%3D2020%0A%0ACREATE%20UNIQUE%20CLUSTERED%20Index%20Data_Per_Day_29_09_2020_X1%20ON%20Data_Per_Day_29_09_2020(ID)%0A%3C%2FCODE%3E%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CUL%3E%0A%3CUL%3E%0A%3CLI%3EWhen%20you%20have%20an%20indexed%20view%20the%20data%20will%20be%20automatically%20saved%20as%20materialized%20data%2C%20so%2C%20in%20every%20row%20that%20you%20added%20in%20the%20table%20depending%20on%20the%20value%20of%20the%20field%20DATE%20you%20are%20going%20to%20have%20a%20materialized%20view%20with%20data.%20If%20you%20run%20the%20query%20using%20this%20view%20SELECT%20*%20FROM%20Data_Per_Day_29_09_2020%20WITH%20(NOEXPAND)%20the%20data%20that%20you%20are%20going%20to%20have%20is%20the%20materialized%20data%20and%20will%20be%20not%20retrieved%20from%20the%20table.%20If%20you%20use%20SELECT%20*%20FROM%20Data_Per_Day_29_09_2020%20the%20data%20will%20be%20retrieved%20from%20the%20table.%3C%2FLI%3E%0A%3C%2FUL%3E%0A%3C%2FUL%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3EEnjoy!!%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-TEASER%20id%3D%22lingo-teaser-1726198%22%20slang%3D%22en-US%22%3E%3CP%3EToday%2C%20I%20worked%20on%20a%20service%20request%20that%20our%20customer%20has%20an%20internal%20process%20that%20every%20night%20they%20transferred%20data%20from%20table%20(iot_table1)%20to%20another%20table%20(iot_table2)%20based%20on%20several%20filters.%20Despite%20that%20the%20number%20of%20rows%20of%20the%20source%20table%20is%20increasing%20every%20day%2C%20this%20process%20is%20taking%20all%20the%20transaction%20log%20resource%20due%20to%20amount%20of%20data%20that%20this%20process%20is%20transferring.%26nbsp%3B%3C%2FP%3E%3C%2FLINGO-TEASER%3E
Version history
Last update:
‎Sep 30 2020 05:22 PM
Updated by: