2013-06-18 3 views
1

SQL 2008R2 데이터베이스에 커서가 있습니다. 이 커서는 데이터 목록을 가져 와서 각 행의 데이터를 구문 분석 한 다음 저장 프로 시저를 통해 구문 분석 된 데이터 행을 실행합니다.커서를 사용하여 지정된 수의 결과를 반환합니다.

DECLARE ExecsDataCursor CURSOR FAST_FORWARD FOR 
    SELECT TOP (@GuessListSize) 
     ExecutiveId, 
     CompanyExecutiveId, 
     Email, 
     CompanyId, 
     @EmailPatternID EmailPatternID, 
     ExecNameForSorting 
    FROM 
     CompanyExecutive 
    WHERE 
     CurrentlyWithCompany = 1 
     AND 
     Email IS NULL 
     AND 
     CompanyExecutiveId NOT IN 
     (
      SELECT CompanyExecutiveId 
      FROM ExecsData_ExecutiveCandidates 
      WHERE EmailPatternID = @EmailPatternID 
     ) 
    ORDER BY 
     CompanyExecutiveId 

    OPEN ExecsDataCursor 

    DECLARE 
     @ExecutiveId INT, 
     @CompanyExecutiveId INT, 
     @Email NVARCHAR(255), 
     @CompanyId INT, 
     @EmailPatternID_ForCursor TINYINT, 
     @ExecName NVARCHAR(255) 

    FETCH NEXT FROM ExecsDataCursor 
    INTO 
     @ExecutiveId , 
     @CompanyExecutiveId , 
     @Email , 
     @CompanyId , 
     @EmailPatternID_ForCursor, 
     @ExecName 

    DECLARE 
     @FirstName NVARCHAR(50) = '', 
     @MiddleName NVARCHAR(50) = '', 
     @LastName NVARCHAR(50) = '', 
     @ExampleEmail NVARCHAR(255), 
     @Domain NVARCHAR(50) = '' 

    WHILE @@FETCH_STATUS = 0 
    BEGIN 

     IF (SELECT COUNT(*) FROM dbo.splitString(@ExecName,' ')) = 1 
     BEGIN 
      SELECT @FirstName = Data FROM dbo.splitString(@ExecName,' ') WHERE id = 1 
     END 

     IF (SELECT COUNT(*) FROM dbo.splitString(@ExecName,' ')) = 2 
     BEGIN 
      SELECT @FirstName = Data FROM dbo.splitString(@ExecName,' ') WHERE id = 1 
      SELECT @LastName = Data FROM dbo.splitString(@ExecName,' ') WHERE id = 2 
     END 

     IF (SELECT COUNT(*) FROM dbo.splitString(@ExecName,' ')) >= 3 
     BEGIN 
      SELECT @FirstName = Data FROM dbo.splitString(@ExecName,' ') WHERE id = 1 
      SELECT @MiddleName = Data FROM dbo.splitString(@ExecName,' ') WHERE id = 2 
      SELECT @LastName = Data FROM dbo.splitString(@ExecName,' ') WHERE id = (SELECT MAX(id) FROM dbo.splitString(@ExecName,' ')) 
     END 

     SELECT @ExampleEmail = MAX(Email) FROM CompanyExecutive WHERE Email IS NOT NULL AND CompanyId = @CompanyId 
     SELECT @Domain = SUBSTRING(@ExampleEmail, CHARINDEX('@', @ExampleEmail), LEN(@ExampleEmail))    

     IF @EmailPatternID = 1 BEGIN BEGIN TRY EXEC [email protected]_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID END TRY BEGIN CATCH END CATCH END 
     IF @EmailPatternID = 2 BEGIN BEGIN TRY EXEC [email protected]_DataMe @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID END TRY BEGIN CATCH END CATCH END 
     IF @EmailPatternID = 3 BEGIN BEGIN TRY EXEC [email protected]_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID END TRY BEGIN CATCH END CATCH END 
     IF @EmailPatternID = 4 BEGIN BEGIN TRY EXEC [email protected]_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID END TRY BEGIN CATCH END CATCH END 
     IF @EmailPatternID = 5 BEGIN BEGIN TRY EXEC [email protected]_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID END TRY BEGIN CATCH END CATCH END 
     IF @EmailPatternID = 6 BEGIN BEGIN TRY EXEC [email protected]_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID END TRY BEGIN CATCH END CATCH END 
     IF @EmailPatternID = 7 BEGIN BEGIN TRY EXEC [email protected]_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID END TRY BEGIN CATCH END CATCH END 
     IF @EmailPatternID = 8 BEGIN BEGIN TRY EXEC [email protected]_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID END TRY BEGIN CATCH END CATCH END 
     IF @EmailPatternID = 9 BEGIN BEGIN TRY EXEC [email protected]_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID END TRY BEGIN CATCH END CATCH END 
     IF @EmailPatternID = 10 BEGIN BEGIN TRY EXEC [email protected]_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID END TRY BEGIN CATCH END CATCH END 
     IF @EmailPatternID = 11 BEGIN BEGIN TRY EXEC [email protected]_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID END TRY BEGIN CATCH END CATCH END 
     IF @EmailPatternID = 12 BEGIN BEGIN TRY EXEC [email protected]_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID END TRY BEGIN CATCH END CATCH END 
     IF @EmailPatternID = 13 BEGIN BEGIN TRY EXEC [email protected]_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID END TRY BEGIN CATCH END CATCH END 

      FETCH NEXT FROM ExecsDataCursor 
       INTO 
        @ExecutiveId , 
        @CompanyExecutiveId , 
        @Email , 
        @CompanyId , 
        @EmailPatternID_ForCursor, 
        @ExecName 
    END 
    CLOSE ExecsDataCursor 
    DEALLOCATE ExecsDataCursor 

적어도 내 기대치에 따라 매우 효과적입니다. 커서는 약 19 초 동안 8000 개의 행을 처리합니다. 8000 행은 @GuessListSize 매개 변수에 공급되는 사용자 입력에 의해 지정됩니다. 그러나 구문 분석 된 데이터가 항상 올바르게 처리되는 것은 아니므로 예상 할 수 있습니다. 따라서 try-catch 코드. 우리는 커서가 실패한 저장 프로 시저 실행에 대해 아무 것도 할 필요가 없습니다. 우리는 이들을 별도의 테이블에서 추적하기 시작 했으므로 미래에 이러한 데이터 포인트를 더 잘 처리하는 방법을 찾아 낼 수 있습니다.

이 문제는 이제 커서가 전체 목록을 반환하지 않는다는 것입니다. 우리는 사용자가 지정한 크기 목록을 원합니다. 따라서 커서는 지정된 크기의 목록을 가져 오지 만 일부 항목은 저장 프로 시저에서 올바르게 처리되지 않아 지정된 크기보다 작은 목록을 반환 할 수 있습니다.

그럼 내가 시도한 것은 반복 루프입니다. 자, WHILE 루프가 잘 작동했습니다. 사용자가 요청한 행을 모두 반환했습니다. 그러나 동일한 크기의 데이터 세트를 실행하는 데는 거의 30 분이 걸렸습니다. 이것은 분명히 받아 들일 수 없다. 커서가 데이터의 미리 정의 된 목록을 씹을 수 있도록 설계되었습니다

DECLARE 
     @ExecutiveId INT, 
     @CompanyExecutiveId INT, 
     @Email NVARCHAR(255), 
     @CompanyId INT, 
     @EmailPatternID_ForCursor TINYINT, 
     @ExecName NVARCHAR(255) 


    DECLARE 
     @FirstName NVARCHAR(50) = '', 
     @MiddleName NVARCHAR(50) = '', 
     @LastName NVARCHAR(50) = '', 
     @ExampleEmail NVARCHAR(255), 
     @Domain NVARCHAR(50) = '', 
     @Counter SMALLINT = 0 

    --WHILE @@FETCH_STATUS = 0 
    WHILE @Counter < @GuessListSize 
    BEGIN 

     SELECT @CompanyExecutiveId = 
      MIN(CompanyExecutiveID) 
     FROM CompanyExecutive 
     WHERE CurrentlyWithCompany = 1 AND Email IS NULL 
      AND 
      CompanyExecutiveId NOT IN 
      (SELECT CompanyExecutiveId FROM ExecsData_ExecutiveCandidates WHERE EmailPatternID = @EmailPatternID) 
      AND 
      CompanyExecutiveID NOT IN 
      (SELECT CompanyExecutiveId FROM ExecsData_Errors) 

     SELECT 
      @ExecutiveId = ExecutiveId, 
      @Email = Email, 
      @CompanyId = CompanyId, 
      @EmailPatternID_ForCursor = @EmailPatternID, 
      @ExecName = ExecNameForSorting 
     FROM 
      CompanyExecutive 
     WHERE 
      CompanyExecutiveId = @CompanyExecutiveId 

     IF (SELECT COUNT(*) FROM dbo.splitString(@ExecName,' ')) = 1 
     BEGIN 
      SELECT @FirstName = Data FROM dbo.splitString(@ExecName,' ') WHERE id = 1 
     END 

     IF (SELECT COUNT(*) FROM dbo.splitString(@ExecName,' ')) = 2 
     BEGIN 
      SELECT @FirstName = Data FROM dbo.splitString(@ExecName,' ') WHERE id = 1 
      SELECT @LastName = Data FROM dbo.splitString(@ExecName,' ') WHERE id = 2 
     END 

     IF (SELECT COUNT(*) FROM dbo.splitString(@ExecName,' ')) >= 3 
     BEGIN 
      SELECT @FirstName = Data FROM dbo.splitString(@ExecName,' ') WHERE id = 1 
      SELECT @MiddleName = Data FROM dbo.splitString(@ExecName,' ') WHERE id = 2 
      SELECT @LastName = Data FROM dbo.splitString(@ExecName,' ') WHERE id = (SELECT MAX(id) FROM dbo.splitString(@ExecName,' ')) 
     END 

     SELECT @ExampleEmail = MAX(Email) FROM CompanyExecutive WHERE Email IS NOT NULL AND CompanyId = @CompanyId 
     SELECT @Domain = SUBSTRING(@ExampleEmail, CHARINDEX('@', @ExampleEmail), LEN(@ExampleEmail)) 

    IF @EmailPatternID = 1 BEGIN BEGIN TRY EXEC [email protected]_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID; SET @Counter = @Counter + 1; END TRY BEGIN CATCH INSERT INTO ExecsData_Errors (CompanyExecutiveID,EmailPatternID) VALUES (@CompanyExecutiveId,@EmailPatternID) END CATCH END 
    IF @EmailPatternID = 2 BEGIN BEGIN TRY EXEC [email protected]_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID; SET @Counter = @Counter + 1; END TRY BEGIN CATCH INSERT INTO ExecsData_Errors (CompanyExecutiveID,EmailPatternID) VALUES (@CompanyExecutiveId,@EmailPatternID) END CATCH END 
    IF @EmailPatternID = 3 BEGIN BEGIN TRY EXEC [email protected]_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID; SET @Counter = @Counter + 1; END TRY BEGIN CATCH INSERT INTO ExecsData_Errors (CompanyExecutiveID,EmailPatternID) VALUES (@CompanyExecutiveId,@EmailPatternID) END CATCH END 
    IF @EmailPatternID = 4 BEGIN BEGIN TRY EXEC [email protected]_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID; SET @Counter = @Counter + 1; END TRY BEGIN CATCH INSERT INTO ExecsData_Errors (CompanyExecutiveID,EmailPatternID) VALUES (@CompanyExecutiveId,@EmailPatternID) END CATCH END 
    IF @EmailPatternID = 5 BEGIN BEGIN TRY EXEC [email protected]_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID; SET @Counter = @Counter + 1; END TRY BEGIN CATCH INSERT INTO ExecsData_Errors (CompanyExecutiveID,EmailPatternID) VALUES (@CompanyExecutiveId,@EmailPatternID) END CATCH END 
    IF @EmailPatternID = 6 BEGIN BEGIN TRY EXEC [email protected]_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID; SET @Counter = @Counter + 1; END TRY BEGIN CATCH INSERT INTO ExecsData_Errors (CompanyExecutiveID,EmailPatternID) VALUES (@CompanyExecutiveId,@EmailPatternID) END CATCH END 
    IF @EmailPatternID = 7 BEGIN BEGIN TRY EXEC [email protected]_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID; SET @Counter = @Counter + 1; END TRY BEGIN CATCH INSERT INTO ExecsData_Errors (CompanyExecutiveID,EmailPatternID) VALUES (@CompanyExecutiveId,@EmailPatternID) END CATCH END 
    IF @EmailPatternID = 8 BEGIN BEGIN TRY EXEC [email protected]_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID; SET @Counter = @Counter + 1; END TRY BEGIN CATCH INSERT INTO ExecsData_Errors (CompanyExecutiveID,EmailPatternID) VALUES (@CompanyExecutiveId,@EmailPatternID) END CATCH END 
    IF @EmailPatternID = 9 BEGIN BEGIN TRY EXEC [email protected]_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID; SET @Counter = @Counter + 1; END TRY BEGIN CATCH INSERT INTO ExecsData_Errors (CompanyExecutiveID,EmailPatternID) VALUES (@CompanyExecutiveId,@EmailPatternID) END CATCH END 
    IF @EmailPatternID = 10 BEGIN BEGIN TRY EXEC [email protected]_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID; SET @Counter = @Counter + 1; END TRY BEGIN CATCH INSERT INTO ExecsData_Errors (CompanyExecutiveID,EmailPatternID) VALUES (@CompanyExecutiveId,@EmailPatternID) END CATCH END 
    IF @EmailPatternID = 11 BEGIN BEGIN TRY EXEC [email protected]_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID; SET @Counter = @Counter + 1; END TRY BEGIN CATCH INSERT INTO ExecsData_Errors (CompanyExecutiveID,EmailPatternID) VALUES (@CompanyExecutiveId,@EmailPatternID) END CATCH END 
    IF @EmailPatternID = 12 BEGIN BEGIN TRY EXEC [email protected]_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID; SET @Counter = @Counter + 1; END TRY BEGIN CATCH INSERT INTO ExecsData_Errors (CompanyExecutiveID,EmailPatternID) VALUES (@CompanyExecutiveId,@EmailPatternID) END CATCH END 
    IF @EmailPatternID = 13 BEGIN BEGIN TRY EXEC [email protected]_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID; SET @Counter = @Counter + 1; END TRY BEGIN CATCH INSERT INTO ExecsData_Errors (CompanyExecutiveID,EmailPatternID) VALUES (@CompanyExecutiveId,@EmailPatternID) END CATCH END 

    END 

때문에, 나는 커서 "동적"와 관계없이 오류의 결과를 사용자가 지정한 수를 반환 말했다 만드는 방법을 모르겠어요. WHILE 루프는 SP가 CATCH 블록을 치지 않고 실행되는 경우에만 "카운터"가 증가하지만 커서를 블록에 통합하는 방법을 알지 못합니다.

여기에 분명한 사실이 있습니까? (요구 된 바와 같이, SQL INSERT의 SP)

ALTER PROCEDURE [dbo].[[email protected]_DataMe] 
( 
    @ExecutiveID int, 
    @CompanyExecutiveID int, 
    @FirstName nvarchar(50), 
    @MiddleName nvarchar(50), 
    @LastName nvarchar(50), 
    @DomainName nvarchar(255), 
    @CompanyID int 
) 
AS 

SET NOCOUNT ON 

SET TRANSACTION ISOLATION LEVEL READ COMMITTED 
DECLARE @GUESS nvarchar(255) 

DECLARE @FirstInitial nvarchar(1) 
DECLARE @MiddleInitial nvarchar(1) 
DECLARE @LastInitial nvarchar(1) 

set @FirstInitial = SUBSTRING(@FirstName, 1, 1) 
set @MiddleInitial = SUBSTRING(@MiddleName, 1, 1) 
set @LastInitial = SUBSTRING(@LastName, 1, 1) 

--*****Example****** 
--FirstName = Andy, 
--Middle Name = Xanadu, 
--Last Name = Farag, 
--Domain = @umphreys.com 
--****************** 

--ex. [email protected] 
set @GUESS = LTRIM(@FirstName)+ @DomainName 
EXEC ExecsData_InsertEmailGuessByExec_DataMe 
     @ExecutiveID, 
     @CompanyExecutiveID, 
     @GUESS, 
     @CompanyID, 
     9 


RETURN (@@ERROR) 

ALTER PROCEDURE [dbo].[ExecsData_InsertEmailGuessByExec_DataMe] 
( 
    @ExecutiveID int, 
    @CompanyExecutiveID int, 
    @EmailAddress nvarchar(50), 
    @CompanyID int, 
    @EmailPatternID tinyint 
) 
AS 

BEGIN 
    INSERT ExecsData_ExecutiveCandidates 
    (
     ExecutiveID, 
     CompanyExecutiveID, 
     EmailAddress, 
     CompanyID, 
     EmailPatternID, 
     GuessTimestamp 
    ) 

    VALUES 
    ( 
     @ExecutiveID, 
     @CompanyExecutiveID, 
     @EmailAddress, 
     @CompanyID, 
     @EmailPatternID, 
     CURRENT_TIMESTAMP 
    ) 
END 

당 RBarryYoung의 제안은, 실제 I SP 삽입 프로세스 비트보고 정했다. 내가 발견 한 문제 중 하나는 많은 중역들이 이메일 주소로 연결하기 위해 도메인을 끌어 오지 않고 있다는 것입니다. 스크립트가 도메인 정보를 찾을 수있는 영역을 확장하면 거의 사용자가 지정한 완료로 프로세스가 향상되었습니다. 아직 완벽하지는 않지만 올바른 방향으로 나아가는 단계입니다.

동적으로 커서를 특정 수의 행을 가져 오도록 강제로 찾는 방법은 WHILE 루프를 사용하는 두 번째 SP에서이 특정 SP를 중첩시킬 수 있습니다. 따라서 기본적으로 목록 크기가 사용자 지정 목록 크기보다 작 으면 삽입 SP가 다시 실행됩니다. 그럴 수도 있습니다. 작동하는 경우이를 다시 편집하여 솔루션으로 게시합니다.

+0

'TowerData_guess_ *'절차의 코드는 무엇입니까? – RBarryYoung

+0

이것은 INSERT의 일부로 제공된 구문 분석 된 값을 사용하는 아주 기본적인 INSERT 문입니다. 우리는 100 % 성공적인 삽입을 기대하지 않습니다. 따라서 Cursor가 사용자 지정 개수의 결과에 도달 할 때까지 계속 실행되는 이유입니다. – RockiesMagicNumber

+0

솔직히 나는 19 초를 받아 들일 수 있다고 생각한다. 8000 개의 행을 삽입하는 초보다 더 빠른 것은 대부분의 환경에서 매우 느린 것으로 간주됩니다. proc의 INSERT 코드를 게시하고 때때로 실패 할 것이라고 예상하는 이유를 설명하면, 우리가 더 잘 수행 할 수 있다고 확신합니다. – RBarryYoung

답변

0

게시물의 마지막 단락에서 제안했듯이 중첩 된 SP를 사용하여 종료되었습니다. 가장 바깥 쪽의 SP는 WHILE 루프를 실행하지만 많은 임원을 추적합니다. 그런 다음 지정된 수의 exec로 생성 SP를 실행합니다. 반환 된 숫자가 요청 된 숫자보다 작 으면 WHILE 루프에 남아 있습니다.

생성 SP의 오류가 Google 데이터 팀에 의해 검토되기 위해 기록됩니다.

관련 문제