ahmed_sa Ответов: 3

Как написать цикл ниже с наилучшей производительностью практики ?


I work on SQL server 2012

I have temp table get data from excel and based on data exist on excel i insert on table inside loop

temp table always have big amount of data may be at least 5000 or 10000 or 15000

I need every iteration increased by 5000 rows insert from temp table 

so that i need best solutions for that according to speed and memory like that 

and if there are any thing not correct as logic please tell me

my Query as below :


Что я уже пробовал:

Create Table [dbo].PartsData
(
    BatchID nvarchar(50) primary key,
    RowNumber int,
    GivenPartNumber nvarchar(50),
	GivenManufacturer nvarchar(100)

)

--select * from [dbo].PartsData
Create Table [dbo].[Type_ValidationInPut]
(
    RowNumber int,
    GivenPartNumber nvarchar(50),
	GivenManufacturer nvarchar(100)

)

create table #Temp(
	DocumentPartID int identity(1,1),
	CompanyName VARCHAR(4000),
	[AffectedProduct] NVARCHAR(4000),
	[ReplacementPart] VARCHAR(4000) , 
	[ReplacementCompany] VARCHAR(4000) ,
	[Category] VARCHAR(4000) ,

    
	DocumentID int null,  
	CompanyID VARCHAR(4000) null,
	PartID int null,
	ReplacementPartID int null,
	CategoryID  int null,
	[Status]  VARCHAR(4000) null ,


)



insert into #Temp
(
CompanyName ,
[AffectedProduct],
[ReplacementPart],
[ReplacementCompany],
[Category]
)  
values
('Nokia','RF1550','RF1550','HTS','HTS'),
('IPHONE','TF1545','TF1545','Corning Incorporated','HTS2')



DECLARE @MaxValue int = ( select Max(DocumentPartID) from #Temp)
DECLARE @Currentindex int =0

DECLARE @Rows  [dbo].[Type_ValidationInPut];	
		   while @Currentindex < @MaxValue
            begin 
			
		  
              DELETE @Rows
              INSERT  INTO @Rows
		                (
						RowNumber ,
				 GivenPartNumber ,
                  GivenManufacturer       
                ) 
           
		   
			select TOP 5000 DocumentPartID , isnull(AffectedProduct,''), isnull(CompanyName,'') FROM #Temp where 
			
			(CategoryID = 517884 or CategoryID = 1110481)  and (DocumentPartID > @Currentindex) and [Status] is null 

			    INSERT  INTO @Rows
		                (
                 RowNumber ,
				 GivenPartNumber ,
                  GivenManufacturer       
                ) 
             
		
			select TOP 5000 DocumentPartID, isnull(substring(ReplacementPart,0,70),''), isnull(ReplacementCompany,'') FROM #Temp where   
			(DocumentPartID > @Currentindex) and  [Status] is null and ReplacementPart is not null
		

			DECLARE @NewID nVARCHAR(4000) =newID()
			insert into [dbo].PartsData (BatchID,RowNumber,GivenPartNumber,givenmanufacturer) 
			SELECT  @NewID ,0,GivenPartNumber,GivenManufacturer from  @Rows 
			

			
			set @Currentindex = @Currentindex +5000
			DELETE @Rows
             end

3 Ответов

Рейтинг:
22

MadMyche

Первое, что бросилось мне в глаза в этом случае, был плохой выбор в объявлении переменной.
Я не вижу для этого веской причины, так как @NewID всегда будет иметь один и тот же размер; вам было бы лучше использовать его NCHAR(37)

DECLARE @NewID nVARCHAR(4000) =newID()
Естественно, чтобы попытаться помочь вам, я скопировал/вставил ваш код в SSMS и начал с переформатирования.

Ваша таблица #temp сама запрашивает загрузку памяти. Знаете ли вы, что в SQL Server существует ограничение длины строки 8060? Как только вы нажмете пересечь этот порог, потребуется несколько страниц памяти, чтобы удерживать каждую строку. Поскольку он находится прямо сейчас, ваша таблица значительно превышает 32 000 байт.
Вам действительно нужно определить каждое нецелочисленное число как 4000 символов длиной?
create table #Temp(
   DocumentPartID      int identity(1,1),
   CompanyName         VARCHAR(4000),
   AffectedProduct     NVARCHAR(4000),
   ReplacementPart     VARCHAR(4000) , 
   ReplacementCompany  VARCHAR(4000) ,
   Category            VARCHAR(4000) ,
   
   DocumentID         int null,  
   CompanyID          VARCHAR(4000) null,
   PartID             int null,
   ReplacementPartID  int null,
   CategoryID         int null,
   [Status]           VARCHAR(4000) null
)
Как только я получаю все это красиво отформатированное во что-то читаемое, я замечаю еще несколько вещей:

1. Либо есть какой-то код отсутствует, или ваша первая инструкция никогда не будет пожара; как categoryId никогда не заполняется.

2. Первый и последний элементы в вашем цикле удаляются одновременно @Грядки. Должно быть сделано только один раз в цикле.

Если эта процедура будет использоваться часто, я бы рекомендовал вам создать для нее пакет SSIS (ETL: Extract-Transform-Load), который будет иметь гораздо меньшее влияние на ваши ресурсы SQL Server и работать гораздо быстрее, а также может легко обрабатывать миллиарды записей.


ahmed_sa

Хорошо а как насчет select top 5000 exist inside loop
это нормально или у вас что-то не так

ahmed_sa

я могу оставить мой запрос без использования во время решения петля

MadMyche

Конечно, это возможно, но это зависит от вас.
Вам нужно выяснить, что вам действительно нужно для дизайна и тонкой настройки оттуда.
У меня нет ни всей информации, ни времени, чтобы сделать то, что может понадобиться здесь.

ahmed_sa

Я обновляю свой запрос скрипта полностью, так что вы можете мне помочь, пожалуйста, если p[ossible
если есть какое-либо решение без использования цикла while

Jörgen Andersson

Это Варчары, поэтому они на самом деле не занимают больше места, чем нужно.
Тем не менее, никогда не следует определять столбец больше, чем это необходимо, поскольку это является частью проверки здравомыслия данных.

ahmed_sa

Хорошо это я сделаю и пока петля какая альтернатива ей

Рейтинг:
1

Jörgen Andersson

Один из способов выполнения пакетных вставок:

DECLARE @Batchsize INT = 5000;
DECLARE @RowCount INT = @Batchsize;
DECLARE @LastID INT;

WHILE @RowCount = @Batchsize
BEGIN
    SET @LastID = (
            SELECT ISNULL(max(MyTableID), - 1)
            FROM MyTable
            );

    INSERT INTO MyTable (MyTableID,OtherColumns)
    SELECT  TOP (@Batchsize) 
            MyTableID
           ,OtherColumns
    FROM    TheSourceTable
    WHERE   MyTableID > @LastID
    ORDER BY MyTableID;

    SET @RowCount = @@ROWCOUNT;
END;
Отрегулируйте по мере необходимости


Рейтинг:
0

MarcusCole6833

Переходя от решения один и используя процесс ETL, вы можете использовать дату импорта из задач в базе данных

щелкните правой кнопкой мыши на базе данных

и получил задачи, а затем на задачах выберите Импорт данных. Появится мастер MSFT и проследите за ним до excel, и файл excel можно будет сопоставить с таблицей

смотрите ссылку ниже

Импорт и экспорт данных с помощью мастера импорта и экспорта SQL Server - SQL Server Integration Services (SSIS) | Microsoft Docs[^]