SnowConvert AI - 일반 성능 검토 메시지

SSC-PRF-0001

이 문에서 커서 가져오기 대량 작업이 사용됩니다

설명

이 경고는 문이 커서 가져오기 대량 작업을 사용한다는 것을 나타냅니다. 이러한 작업을 사용하면 커서에서 한 번에 한 행씩이 아니라 여러 행의 데이터를 한 번에 검색할 수 있습니다. 대량 작업을 사용하면 클라이언트와 서버 간에 필요한 통신 횟수가 줄어들어 성능이 향상됩니다.

이 패턴은 올바르게 구현하지 않으면 복잡해질 수 있습니다. 예를 들어, 한 번의 가져오기 작업에서 너무 많은 행을 검색하면 메모리가 과도하게 소모될 수 있습니다. 가져오는 행 수와 사용 가능한 메모리 리소스 간의 균형을 유지하는 것이 중요합니다.

코드 예제

Oracle

입력
 CREATE OR REPLACE PROCEDURE oracle_cursor_fetch_bulk AS
--cursor and variable declarations
BEGIN
    OPEN c1;
    FETCH c1 BULK COLLECT INTO col1;
    CLOSE c1;
END;
Copy
출력
 CREATE OR REPLACE PROCEDURE oracle_cursor_fetch_bulk ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
--cursor and variable declarations
$$
    BEGIN
        OPEN c1;
        --** SSC-PRF-0001 - THIS STATEMENT HAS USAGES OF CURSOR FETCH BULK OPERATIONS **
        c1 := (
            CALL FETCH_BULK_COLLECTION_RECORDS_UDF(:c1)
        );
        col1 := :c1:RESULT;
        CLOSE c1;
    END;
$$;
Copy

모범 사례

SSC-PRF-0002

대소문자를 구분하지 않는 열로 인해 쿼리 성능이 저하될 수 있습니다

설명

Snowflake에서 데이터 정렬을 사용하면 특히 WHERE 절에서 쿼리 성능에 영향을 미칠 수 있습니다. 데이터 정렬이 성능에 미치는 영향에 대해 자세히 알아보려면 데이터 정렬 사용의 성능 영향 을 참조하십시오.

대/소문자를 구분하지 않는 데이터 정렬로 열이 생성되었음을 나타내는 경고가 생성되었습니다. 쿼리에서 이 열을 사용하면 성능이 저하될 수 있습니다.

코드 예

출력

 CREATE TABLE exampleTable
(
    col1 CHAR(10),
    col2 CHAR(20) COLLATE 'en-ci' /*** SSC-PRF-0002 - CASE INSENSITIVE COLUMNS CAN DECREASE THE PERFORMANCE OF QUERIES ***/
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"teradata"}}'
;
Copy

Oracle

입력
 CREATE TABLE exampleTable (
    col1 VARCHAR(50) COLLATE BINARY_CI,
    col2 VARCHAR(50) COLLATE BINARY_CS
);
Copy
출력
 CREATE OR REPLACE TABLE exampleTable (
       col1 VARCHAR(50) COLLATE BINARY_CI /*** SSC-PRF-0002 - CASE INSENSITIVE COLUMNS CAN DECREASE THE PERFORMANCE OF QUERIES ***/,
       col2 VARCHAR(50) COLLATE BINARY_CS
   )
   COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
   ;
Copy

Microsoft SQL 서버

입력
 CREATE TABLE exampleTable (
    col1 VARCHAR(50) COLLATE Latin1_General_CI_AS,
    col2 VARCHAR(50) COLLATE Latin1_General_CS_AS
);
Copy
출력
 CREATE OR REPLACE TABLE exampleTable (
    col1 VARCHAR(50) COLLATE 'EN-CI-AS' /*** SSC-PRF-0002 - CASE INSENSITIVE COLUMNS CAN DECREASE THE PERFORMANCE OF QUERIES ***/,
    col2 VARCHAR(50) COLLATE 'EN-CS-AS'
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
;
Copy

모범 사례

  • 대/소문자를 구분하지 않는 데이터 정렬로 인해 애플리케이션의 성능이 크게 영향을 받는다면 해당 기능을 사용하지 않도록 코드를 다시 작성하는 것이 좋습니다. 그러나 성능에 미치는 영향이 허용 가능한 수준이라면 이 경고를 무시해도 됩니다.

  • 추가 지원이 필요하면 snowconvert-support@Snowflake.com으로 문의해 주십시오.

SSC-PRF-0003

루프 내부의 가져오기는 복잡한 패턴으로 간주되므로 Snowflake 성능을 저하시킬 수 있습니다

심각도

낮음

설명

이 경고는 루프 내에서 FETCH 문이 감지될 때 표시됩니다. FETCH 문은 결과 세트에서 개별 행을 한 번에 1개씩 검색하고 처리합니다.

특히 루프 내에서 커서를 사용하여 대규모 데이터 세트를 처리하는 것은 복잡해질 수 있습니다.

  • 여러 테이블 조인이 관련된 경우

  • 복잡한 계산이 필수 경우

  • 많은 수의 행을 처리해야 하는 경우

이 패턴은 성능 문제를 일으킬 수 있으며 데이터 볼륨이 증가함에 따라 유지 관리가 어려울 수 있습니다.

코드 예제

Teradata

입력
 REPLACE PROCEDURE teradata_fetch_inside_loop()
DYNAMIC RESULT SETS 1
BEGIN
    DECLARE col_name VARCHAR(200);
    DECLARE col_int INTEGER DEFAULT 0;
    DECLARE cursor_var CURSOR FOR SELECT some_column FROM tabla1;
    WHILE (col_int <> 0) DO		
        FETCH cursor_var INTO col_name;
        SET col_int = col_int + 1;
    END WHILE;
END;
Copy
출력
 --** SSC-FDM-0007 - MISSING DEPENDENT OBJECT "tabla1" **
CREATE OR REPLACE PROCEDURE teradata_fetch_inside_loop ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": {  "major": 0,  "minor": 0,  "patch": "0" }, "attributes": {  "component": "teradata",  "convertedOn": "07/02/2025",  "domain": "no-domain-provided" }}'
EXECUTE AS CALLER
AS
$$
    DECLARE
        col_name VARCHAR(200);
        col_int INTEGER DEFAULT 0;
    BEGIN
         
         
        LET cursor_var CURSOR
        FOR
            SELECT
                some_column FROM
                tabla1;
                WHILE (:col_int <> 0) LOOP
            --** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
                    FETCH cursor_var INTO col_name;
            col_int := col_int + 1;
                END LOOP;
    END;
$$;
Copy

Oracle

입력
 CREATE PROCEDURE oracle_fetch_inside_loop
IS
  var1 table1.column1%TYPE;
  CURSOR cursor1 IS SELECT COLUMN_NAME FROM table1; 
BEGIN
  WHILE true LOOP
    FETCH cursor1 INTO var1;
    EXIT WHEN cursor1%NOTFOUND;
  END LOOP;  
END;
Copy
출력
 CREATE OR REPLACE PROCEDURE oracle_fetch_inside_loop ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": {  "major": 0,  "minor": 0,  "patch": "0" }, "attributes": {  "component": "oracle",  "convertedOn": "07/02/2025",  "domain": "no-domain-provided" }}'
EXECUTE AS CALLER
AS
$$
  DECLARE
    var1 VARIANT !!!RESOLVE EWI!!! /*** SSC-EWI-OR0129 - TYPE ATTRIBUTE 'table1.column1%TYPE' COULD NOT BE RESOLVED, SO IT WAS TRANSFORMED TO VARIANT ***/!!!;
    --** SSC-PRF-0009 - PERFORMANCE REVIEW - CURSOR USAGE **
    cursor1 CURSOR
    FOR
      SELECT COLUMN_NAME FROM
        table1;
  BEGIN
    WHILE (true)
                 --** SSC-PRF-0008 - PERFORMANCE REVIEW - LOOP USAGE **
                 LOOP
      --** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
         FETCH cursor1 INTO
        :var1;
         IF (var1 IS NULL) THEN
        EXIT;
         END IF;
       END LOOP;
  END;
$$;
Copy

SQL 서버

입력
 CREATE OR ALTER PROCEDURE transact_fetch_inside_loop
AS
BEGIN
    DECLARE cursor1 CURSOR
        FOR SELECT col1 FROM my_table;
    WHILE 1=0
    BEGIN
       FETCH NEXT FROM @cursor1 INTO @variable1;
    END
END;
Copy
출력
 CREATE OR REPLACE PROCEDURE transact_fetch_inside_loop ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
    DECLARE
        --** SSC-FDM-TS0013 - SNOWFLAKE SCRIPTING CURSOR ROWS ARE NOT MODIFIABLE **
        cursor1 CURSOR
        FOR
            SELECT
                col1
            FROM
                my_table;
    BEGIN
         
        WHILE (1=0) LOOP
            --** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
            FETCH
                CURSOR1
                INTO
                :VARIABLE1;
        END LOOP;
    END;
$$;
Copy

모범 사례

  • 성능을 개선하고 복잡한 패턴을 피하려면 루프 대신 세트 기반 작업을 사용하십시오. 행 단위 처리를 WHERE 절을 사용하여 여러 행에서 동시에 작업하는 SQL 문(SELECT, UPDATE, DELETE)로 바꿉니다. 이 접근법이 더 효율적이고 유지 관리가 쉽습니다.

Oracle

 CREATE OR REPLACE PROCEDURE cursor_fetch_inside_loop 
AS
  record_employee employees%rowtype;
  CURSOR emp_cursor IS SELECT * FROM employees;
BEGIN
  OPEN emp_cursor;
  LOOP
    FETCH emp_cursor INTO record_employee;
    EXIT WHEN emp_cursor%notfound;
    INSERT INTO new_employees VALUES (record_employee.first_name, record_employee.last_name);
  END LOOP;
  CLOSE emp_cursor;
END;
Copy

Snowflake

 CREATE OR REPLACE PROCEDURE cursor_fetch_inside_loop ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": {  "major": 0,  "minor": 0,  "patch": "0" }, "attributes": {  "component": "oracle",  "convertedOn": "07/02/2025",  "domain": "no-domain-provided" }}'
EXECUTE AS CALLER
AS
$$
  DECLARE
    record_employee OBJECT !!!RESOLVE EWI!!! /*** SSC-EWI-0036 - ROWTYPE DATA TYPE CONVERTED TO OBJECT ***/!!! := OBJECT_CONSTRUCT();
    --** SSC-PRF-0009 - PERFORMANCE REVIEW - CURSOR USAGE **
    emp_cursor CURSOR
    FOR
      SELECT
        OBJECT_CONSTRUCT( *) sc_cursor_record FROM
        employees;
  BEGIN
    OPEN emp_cursor;
    --** SSC-PRF-0008 - PERFORMANCE REVIEW - LOOP USAGE **
    LOOP
      --** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
      FETCH emp_cursor INTO
        :record_employee;
      IF (record_employee IS NULL) THEN
        EXIT;
      END IF;
      INSERT INTO new_employees
      SELECT
        :record_employee:FIRST_NAME,
        :record_employee:LAST_NAME;
    END LOOP;
  CLOSE emp_cursor;
  END;
$$;
Copy

세트 기반 작업을 사용하면 데이터를 보다 효율적으로 처리할 수 있습니다.

 CREATE OR REPLACE PROCEDURE cursor_fetch_inside_loop AS
BEGIN
  INSERT INTO new_employees (first_name, last_name)
  SELECT first_name, last_name FROM employees;
END;
Copy

세트 기반 작업을 사용하면 데이터를 보다 효율적으로 처리할 수 있습니다.

 CREATE OR REPLACE PROCEDURE cursor_fetch_inside_loop ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
  BEGIN
    INSERT INTO new_employees(first_name, last_name)
    SELECT first_name, last_name FROM
      employees;
  END;
$$;
Copy

모범 사례

SSC-PRF-0004

이 문에서 cursor for loop가 사용됩니다

심각도

없음

설명

이 경고는 문에 루프용 커서가 포함되어 있음을 나타냅니다. 루프용 커서는 쿼리 결과를 한 번에 한 행씩 처리하는 프로그래밍 구조로, 결과 세트의 개별 레코드로 작업할 수 있습니다.

이 경고는 커서 FOR 루프의 잠재적인 성능 문제를 식별하는 데 도움이 됩니다. 성능 문제가 발생할 수 있습니다.

  • 커서 내에 있는 SELECT 문은 큰 데이터 세트를 반환합니다

  • 루프에는 복잡한 작업이 포함되어 있습니다

  • 루프에는 중첩된 루프가 포함됩니다

SnowConvert AI는 이러한 패턴을 감지할 수 있지만 효율적인 실행을 보장하기 위해 코드를 검토하고 최적화해야 합니다.

코드 예제

Teradata

입력
 REPLACE PROCEDURE teradata_cursor_for_loop()    
BEGIN
    FOR fUsgClass AS cUsgClass CURSOR FOR
        (SELECT col1
        FROM sample_table)
    DO
        SET var1 = fUsgClass.col1;
    END FOR;
END;
Copy
출력
 --** SSC-FDM-0007 - MISSING DEPENDENT OBJECT "sample_table" **
CREATE OR REPLACE PROCEDURE teradata_cursor_for_loop ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": {  "major": 0,  "minor": 0,  "patch": "0" }, "attributes": {  "component": "teradata",  "convertedOn": "07/16/2025",  "domain": "no-domain-provided" }}'
EXECUTE AS CALLER
AS
$$
    DECLARE
        !!!RESOLVE EWI!!! /*** SSC-EWI-0110 - TRANSFORMATION NOT PERFORMED DUE TO MISSING DEPENDENCIES ***/!!!
        temp_fUsgClass_col1;
    BEGIN
        LET cUsgClass CURSOR
        FOR
            SELECT
                col1
                   FROM
                sample_table;
        --** SSC-PRF-0004 - THIS STATEMENT HAS USAGES OF CURSOR FOR LOOP **
        FOR fUsgClass IN cUsgClass DO
            temp_fUsgClass_col1 := fUsgClass.col1;
            var1 := :temp_fUsgClass_col1;
        END FOR;
    END;
$$;
Copy

Oracle

입력
 CREATE OR REPLACE PROCEDURE oracle_cursor_for_loop AS
BEGIN
    FOR r1 IN (SELECT col1 FROM sample_table) LOOP
        NULL;
    END LOOP;
END;
Copy
출력
 CREATE OR REPLACE PROCEDURE oracle_cursor_for_loop ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
    BEGIN
        LET temporary_for_cursor_0 CURSOR
        FOR
            (SELECT col1 FROM
                    sample_table
            );
        --** SSC-PRF-0004 - THIS STATEMENT HAS USAGES OF CURSOR FOR LOOP **
        FOR r1 IN temporary_for_cursor_0 DO
            NULL;
        END FOR;
    END;
$$;
Copy

모범 사례

SSC-PRF-0005

아래 문에서 중첩 커서가 사용됩니다

참고

가독성을 높이기 위해 이 예제에서는 코드의 일부 섹션을 간소화했습니다.

심각도

없음

설명

이 경고는 문에 중첩된 커서가 포함되어 있음을 나타냅니다. 커서는 쿼리 결과의 행을 한 번에 1개씩 처리할 수 있는 데이터베이스 기능입니다. 중첩 커서는 한 커서를 다른 커서의 루프 안에 사용할 때 발생하며, 성능에 영향을 줄 수 있으므로 주의해서 사용해야 합니다.

중첩된 커서는 특히 많은 양의 데이터로 작업할 때 코드의 성능을 크게 저하시킬 수 있습니다. 커서가 작업할 때마다 데이터베이스 서버와 통신해야 하므로 추가적인 처리 오버헤드와 지연이 발생하기 때문입니다.

코드 예

SQL 서버

입력
 CREATE OR ALTER PROCEDURE procedureSample
AS
BEGIN
  DECLARE
    @outer_category_id INT,
    @outer_category_name NVARCHAR(50),
    @inner_product_name NVARCHAR(50);

  -- Define the outer cursor
  DECLARE outer_cursor CURSOR FOR 
    SELECT category_id, category_name FROM categories;

  -- Open the outer cursor
  OPEN @outer_cursor;

  -- Fetch the first row from the outer cursor
  FETCH NEXT FROM outer_cursor INTO @outer_category_id, @outer_category_name;

  -- Start the outer loop
  WHILE @@FETCH_STATUS = 0
  BEGIN

    PRINT 'Category: ' + @outer_category_name;
	
    -- Define the inner cursor
    DECLARE inner_cursor CURSOR FOR
      SELECT product_name FROM products WHERE category_id = @outer_category_id;
    
    -- Open the inner cursor
    OPEN inner_cursor;
	FETCH NEXT FROM inner_cursor INTO @inner_product_name;

    WHILE @@FETCH_STATUS = 0
    BEGIN
      PRINT 'Product: ' + @inner_product_name + ' Category: ' + CAST(@outer_category_id AS NVARCHAR(10));

      -- Fetch the next row from the inner cursor
      FETCH NEXT FROM inner_cursor INTO @inner_product_name;
    END;

    -- Close the inner cursor
    CLOSE inner_cursor;
    DEALLOCATE inner_cursor;

    -- Fetch the next row from the outer cursor
    FETCH NEXT FROM outer_cursor INTO @outer_category_id, @outer_category_name;
  END;

  -- Close the outer cursor
  CLOSE outer_cursor;
  DEALLOCATE outer_cursor;
  
END;
Copy
출력
 CREATE OR REPLACE PROCEDURE procedureSample ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
	DECLARE
		OUTER_CATEGORY_ID INT;
		OUTER_CATEGORY_NAME VARCHAR(50);
		INNER_PRODUCT_NAME VARCHAR(50);

		-- Define the outer cursor
		--** SSC-FDM-TS0013 - SNOWFLAKE SCRIPTING CURSOR ROWS ARE NOT MODIFIABLE **
		outer_cursor CURSOR
		FOR
			SELECT
				category_id,
				category_name
			FROM
				categories;

		-- Define the inner cursor
		--** SSC-FDM-TS0013 - SNOWFLAKE SCRIPTING CURSOR ROWS ARE NOT MODIFIABLE **
		inner_cursor CURSOR
		FOR
			SELECT
				product_name
			FROM
				products
			WHERE
				category_id = :OUTER_CATEGORY_ID;
	BEGIN
		 
		 

		-- Open the outer cursor
		--** SSC-PRF-0005 - THE STATEMENT BELOW HAS USAGES OF NESTED CURSORS. **
		OPEN OUTER_CURSOR;
  -- Fetch the first row from the outer cursor
		FETCH
			outer_cursor
			INTO
			:OUTER_CATEGORY_ID,
			:OUTER_CATEGORY_NAME;

			-- Start the outer loop

			  -- Define the inner cursor
			WHILE (:FETCH_STATUS = 0) LOOP
			!!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'PRINT' NODE ***/!!!

			  PRINT 'Category: ' + @outer_category_name;
			 

			-- Open the inner cursor
			OPEN inner_cursor;
			--** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
			FETCH
				inner_cursor
			INTO
				:INNER_PRODUCT_NAME;
			WHILE (:FETCH_STATUS = 0) LOOP
				!!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'PRINT' NODE ***/!!!
				PRINT 'Product: ' + @inner_product_name + ' Category: ' + CAST(@outer_category_id AS NVARCHAR(10));
				-- Fetch the next row from the inner cursor
				--** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
				FETCH
					inner_cursor
				INTO
					:INNER_PRODUCT_NAME;
			END LOOP;
			-- Close the inner cursor
			CLOSE inner_cursor;
			!!!RESOLVE EWI!!! /*** SSC-EWI-0058 - FUNCTIONALITY FOR 'DEALLOCATE' IS NOT CURRENTLY SUPPORTED BY SNOWFLAKE SCRIPTING ***/!!!
			  DEALLOCATE inner_cursor;
			-- Fetch the next row from the outer cursor
			--** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
			FETCH
				outer_cursor
			INTO
				:OUTER_CATEGORY_ID,
				:OUTER_CATEGORY_NAME;
			END LOOP;
  -- Close the outer cursor
			CLOSE outer_cursor;
			!!!RESOLVE EWI!!! /*** SSC-EWI-0058 - FUNCTIONALITY FOR 'DEALLOCATE' IS NOT CURRENTLY SUPPORTED BY SNOWFLAKE SCRIPTING ***/!!!
			DEALLOCATE outer_cursor;
	END;
$$;
Copy

Oracle

명시적 커서

입력
 CREATE OR REPLACE PROCEDURE procedureSample AS
BEGIN
DECLARE
  CURSOR outer_cursor IS
    SELECT category_id, category_name FROM categories;

  CURSOR inner_cursor (p_category_id NUMBER) IS
    SELECT product_name FROM products WHERE category_id = p_category_id;

  outer_category_id categories.category_id%TYPE;
  outer_category_name categories.category_name%TYPE;
  inner_product_name products.product_name%TYPE;
BEGIN

  OPEN outer_cursor;
  FETCH outer_cursor INTO outer_category_id, outer_category_name;

  LOOP
    EXIT WHEN outer_cursor%NOTFOUND;
    DBMS_OUTPUT.PUT_LINE('Category: ' || outer_category_name);

    OPEN inner_cursor(outer_category_id);
    LOOP
        FETCH inner_cursor INTO inner_product_name;
        EXIT WHEN inner_cursor%NOTFOUND;
        DBMS_OUTPUT.PUT_LINE('Product: ' || inner_product_name || ' Category: ' || outer_category_id);
    END LOOP;
    CLOSE inner_cursor;

    FETCH outer_cursor INTO outer_category_id, outer_category_name;
  END LOOP;

  CLOSE outer_cursor;
END;
END;
Copy
출력
 CREATE OR REPLACE PROCEDURE procedureSample ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": {  "major": 0,  "minor": 0,  "patch": "0" }, "attributes": {  "component": "oracle",  "convertedOn": "07/02/2025",  "domain": "no-domain-provided" }}'
EXECUTE AS CALLER
AS
$$
  BEGIN
    DECLARE
      --** SSC-PRF-0009 - PERFORMANCE REVIEW - CURSOR USAGE **
      outer_cursor CURSOR
      FOR
        SELECT category_id, category_name FROM
          categories;
      --** SSC-PRF-0009 - PERFORMANCE REVIEW - CURSOR USAGE **
      inner_cursor CURSOR
      FOR
        SELECT product_name FROM
          products
        WHERE category_id = ?;
      outer_category_id VARIANT !!!RESOLVE EWI!!! /*** SSC-EWI-OR0129 - TYPE ATTRIBUTE 'categories.category_id%TYPE' COULD NOT BE RESOLVED, SO IT WAS TRANSFORMED TO VARIANT ***/!!!;
      outer_category_name VARIANT !!!RESOLVE EWI!!! /*** SSC-EWI-OR0129 - TYPE ATTRIBUTE 'categories.category_name%TYPE' COULD NOT BE RESOLVED, SO IT WAS TRANSFORMED TO VARIANT ***/!!!;
      inner_product_name VARIANT !!!RESOLVE EWI!!! /*** SSC-EWI-OR0129 - TYPE ATTRIBUTE 'products.PRODUCT_NAME%TYPE' COULD NOT BE RESOLVED, SO IT WAS TRANSFORMED TO VARIANT ***/!!!;
      call_results VARIANT;
    BEGIN
      --** SSC-PRF-0005 - THE STATEMENT BELOW HAS USAGES OF NESTED CURSORS. **
      OPEN outer_cursor USING ('DEFAULT VALUE NOT FOUND');
      FETCH outer_cursor INTO
        :outer_category_id,
        :outer_category_name;
      --** SSC-PRF-0008 - PERFORMANCE REVIEW - LOOP USAGE **
      LOOP
        IF (outer_category_id IS NULL) THEN
          EXIT;
        END IF;
        --** SSC-FDM-OR0035 - CHECK UDF IMPLEMENTATION FOR DBMS_OUTPUT.PUT_LINE_UDF. **
        call_results := (
          CALL DBMS_OUTPUT.PUT_LINE_UDF('Category: ' || NVL(:outer_category_name :: STRING, ''))
        );
        OPEN inner_cursor USING (:outer_category_id);
        --** SSC-PRF-0008 - PERFORMANCE REVIEW - LOOP USAGE **
        LOOP
          --** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
            FETCH inner_cursor INTO
            :inner_product_name;
          IF (inner_product_name IS NULL) THEN
            EXIT;
          END IF;
          --** SSC-FDM-OR0035 - CHECK UDF IMPLEMENTATION FOR DBMS_OUTPUT.PUT_LINE_UDF. **
          call_results := (
            CALL DBMS_OUTPUT.PUT_LINE_UDF('Product: ' || NVL(:inner_product_name :: STRING, '') || ' Category: ' || NVL(:outer_category_id :: STRING, ''))
          );
        END LOOP;
        CLOSE inner_cursor;
        --** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
        FETCH outer_cursor INTO
          :outer_category_id,
          :outer_category_name;
      END LOOP;
      CLOSE outer_cursor;
      RETURN call_results;
    END;
  END;
$$;
Copy

암시적 커서

입력
 CREATE OR REPLACE PROCEDURE procedureSample AS
BEGIN
DECLARE
   inner_category_id categories.category_name%TYPE;
   inner_product_name products.product_name%TYPE;
   inner_cursor SYS_REFCURSOR;
BEGIN
   FOR outer_cursor IN (SELECT category_id, category_name FROM categories)
   LOOP
      OPEN inner_cursor
       FOR SELECT product_name, category_id FROM products WHERE category_id = outer_cursor.category_id;
      LOOP
         FETCH inner_cursor INTO inner_product_name, inner_category_id;
         EXIT WHEN inner_cursor%NOTFOUND;
         dbms_output.put_line( 'Category id: '|| outer_cursor.category_id);
         dbms_output.put_line('Product name: ' || inner_product_name);
      END LOOP;
      CLOSE inner_cursor;
   END LOOP;
END;
END;
Copy
출력
 CREATE OR REPLACE PROCEDURE procedureSample ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": {  "major": 0,  "minor": 0,  "patch": "0" }, "attributes": {  "component": "oracle",  "convertedOn": "07/02/2025",  "domain": "no-domain-provided" }}'
EXECUTE AS CALLER
AS
$$
   BEGIN
      DECLARE
         inner_category_id VARIANT !!!RESOLVE EWI!!! /*** SSC-EWI-OR0129 - TYPE ATTRIBUTE 'categories.category_name%TYPE' COULD NOT BE RESOLVED, SO IT WAS TRANSFORMED TO VARIANT ***/!!!;
         inner_product_name VARIANT !!!RESOLVE EWI!!! /*** SSC-EWI-OR0129 - TYPE ATTRIBUTE 'products.product_name%TYPE' COULD NOT BE RESOLVED, SO IT WAS TRANSFORMED TO VARIANT ***/!!!;
         inner_cursor_res RESULTSET;
         call_results VARIANT;
      BEGIN
         LET temporary_for_cursor_0 CURSOR
         FOR
            (SELECT category_id, category_name FROM
                  categories
            );
         --** SSC-PRF-0004 - THIS STATEMENT HAS USAGES OF CURSOR FOR LOOP **
         --** SSC-PRF-0005 - THE STATEMENT BELOW HAS USAGES OF NESTED CURSORS. **
         FOR outer_cursor IN temporary_for_cursor_0 DO
            LET inner_cursor CURSOR
            FOR
               SELECT product_name, category_id FROM
                  products
               WHERE category_id = outer_cursor.category_id;
            OPEN inner_cursor;
            --** SSC-PRF-0008 - PERFORMANCE REVIEW - LOOP USAGE **
                 LOOP
               --** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
                    FETCH inner_cursor INTO
                  :inner_product_name,
                  :inner_category_id;
               IF (inner_product_name IS NULL) THEN
                  EXIT;
               END IF;
               --** SSC-FDM-OR0035 - CHECK UDF IMPLEMENTATION FOR DBMS_OUTPUT.PUT_LINE_UDF. **
               call_results := (
                  CALL dbms_output.put_line( 'Category id: ' || NVL(outer_cursor.category_id :: STRING, ''))
               );
               --** SSC-FDM-OR0035 - CHECK UDF IMPLEMENTATION FOR DBMS_OUTPUT.PUT_LINE_UDF. **
               call_results := (
                  CALL dbms_output.put_line('Product name: ' || NVL(:inner_product_name :: STRING, ''))
               );
                 END LOOP;
                 CLOSE inner_cursor;
         END FOR;
         RETURN call_results;
      END;
   END;
$$;
Copy

모범 사례

  • 중첩된 커서는 성능에 부정적인 영향을 미치고 코드를 더 복잡하게 생성할 수 있으므로 피해야 합니다.

  • 중첩된 커서 대신 SQL 기능을 사용합니다.

    • SQL 함수

    • 조인

    • 하위 쿼리

    • 윈도우 함수

    • 일반 테이블 식(CTEs)

    • 재귀 쿼리 이러한 대안은 데이터를 대량으로 처리하며 더 효율적입니다.

  • 추가 지원이 필요하면 snowconvert-support@Snowflake.com으로 문의해 주십시오.

SSC-PRF-0006

쿼리 내부의 중첩 커서는 Snowflake에서 지원되지 않습니다

심각도

없음

설명

쿼리에 커서 정의가 포함된 경우 이 메시지가 표시됩니다. 커서 식이 평가되면 반환되고 중첩된 커서가 자동으로 열립니다. 자세한 내용은 Oracle Cursor 식 을 참조하십시오.

코드 예

입력

 SELECT
  category_id,
  category_name,
  CURSOR (
    SELECT
      product_id,
      product_name || ', ' || category_id
    FROM
      products e
    WHERE
      e.category_id = d.category_id
  ) EMP_CUR
FROM
  categories d;
Copy

출력

 SELECT
  category_id,
  category_name,
  --** SSC-PRF-0006 - NESTED CURSOR INSIDE QUERY IS NOT SUPPORTED IN SNOWFLAKE. **
  CURSOR
    !!!RESOLVE EWI!!! /*** SSC-EWI-0108 - THE FOLLOWING SUBQUERY MATCHES AT LEAST ONE OF THE PATTERNS CONSIDERED INVALID AND MAY PRODUCE COMPILATION ERRORS ***/!!! (
    SELECT
      product_id,
      NVL(
      product_name :: STRING, '') || ', ' || NVL(category_id :: STRING, '')
    FROM
      products e
    WHERE
      e.category_id = d.category_id
  ) EMP_CUR
FROM
  categories d;
Copy

모범 사례

  • 커서는 성능에 부정적인 영향을 미치고 코드를 더 복잡하게 생성할 수 있으므로 피하는 것이 좋습니다.

  • 중첩된 커서를 사용하는 대신 다음과 같은 대안을 고려해 보십시오.

    • SQL 함수

    • 조인

    • 하위 쿼리

    • 윈도우 함수

    • 일반 테이블 식(CTEs)

    • 재귀 쿼리 이 옵션은 많은 양의 데이터를 효율적으로 처리하는 데 더 적합합니다.

  • 추가 지원이 필요하면 snowconvert-support@Snowflake.com으로 문의해 주십시오.

SSC-PRF-0007

PERFORMANCE REVIEW - CLUSTER BY

설명

CLUSTER BY가 사용되어 성능 문제가 발생할 수 있습니다.

코드 예시

Teradata:
 CREATE MULTISET TABLE T_2008,
NO FALLBACK,
NO BEFORE JOURNAL,
NO AFTER JOURNAL,
CHECKSUM = DEFAULT,
DEFAULT MERGEBLOCKRATIO
(
      COL1 NUMBER(20,0) NOT NULL,
      COL2 INTEGER,
      COL3 VARCHAR(4) CHARACTER SET LATIN NOT CASESPECIFIC,
      COL4 DATE FORMAT 'YYYY-MM-DD'
)
PRIMARY INDEX 
( 
      COL1, COL2
)
PARTITION BY ( RANGE_N(COL4 BETWEEN DATE '2010-01-01' AND DATE '2025-12-31' EACH INTERVAL '1' YEAR ),
CASE_N(
COL3  = 'T',
COL3 = 'M',
COL3 = 'L') ); -- PARTITION BY transformed to CLUSTER BY
Copy
Snowflake:
CREATE OR REPLACE TABLE T_2008
(
      COL1 NUMBER(20,0) NOT NULL,
      COL2 INTEGER,
      COL3 VARCHAR(4),
      COL4 DATE
)
--** SSC-PRF-0007 - PERFORMANCE REVIEW - CLUSTER BY **
CLUSTER BY (
             !!!RESOLVE EWI!!! /*** SSC-EWI-0031 - RANGE_N FUNCTION NOT SUPPORTED ***/!!!
             RANGE_N(COL4 BETWEEN DATE '2010-01-01' AND DATE '2025-12-31' EACH INTERVAL '1' YEAR ),
!!!RESOLVE EWI!!! /*** SSC-EWI-0031 - CASE_N FUNCTION NOT SUPPORTED ***/!!!
CASE_N(
COL3  = 'T',
COL3 = 'M',
COL3 = 'L'))
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": {  "major": 0,  "minor": 0,  "patch": "0" }, "attributes": {  "component": "teradata",  "convertedOn": "07/02/2025",  "domain": "no-domain-provided" }}'
; -- PARTITION BY transformed to CLUSTER BY
Copy
Transact:
 CREATE TABLE my_table (
    enterprise_cif INT,
    name NVARCHAR(100),
    address NVARCHAR(255),
    created_at DATETIME
) 
WITH (
    DISTRIBUTION = HASH(enterprise_cif),
    CLUSTERED INDEX (enterprise_cif)
);
Copy
Snowflake:
 CREATE OR REPLACE TABLE my_table (
  enterprise_cif INT,
  name VARCHAR(100),
  address VARCHAR(255),
  created_at TIMESTAMP_NTZ(3)
)
--** SSC-PRF-0007 - PERFORMANCE REVIEW - CLUSTER BY **
CLUSTER BY (enterprise_cif)
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": {  "major": 0,  "minor": 0,  "patch": "0" }, "attributes": {  "component": "transact",  "convertedOn": "10/09/2024" }}'
;
Copy

모범 사례

  • 가능한 성능 문제를 식별하기 위해 코드를 검토합니다. 이 항목에 대한 자세한 내용은 여기에서 확인할 수 있습니다.

  • 추가 지원이 필요한 경우 snowconvert-support@snowflake.com으로 이메일을 보내주세요.

SSC-PRF-0010

Partition by removed, at least one of the specified expressions have no iceberg partition transform equivalent

심각도

없음

설명

Snowflake supports the PARTITION BY clause in Iceberg tables, however, only Iceberg partition transforms are supported. When transforming paritioning into Iceberg tables, SnowConvert AI will generate the equivalent partition transforms for supported cases. When no partition transform equivalent can be generated for the partition expressions, the PARTITION BY will be removed from the table by commenting it out with this PRF.

This PRF is only generated when SnowConvert AI migrates tables into Iceberg tables using the Tables translation conversion setting.

코드 예

입력

 -- Additional Params: --TablesTransformationTarget SnowflakeIceberg
CREATE TABLE FINANCE.FINANCE_TABLE
(
  customerName VARCHAR(30),
  accountBalance VARCHAR(20)
)
PARTITION BY CASE_N(
accountBalance <  0 ,
accountBalance >=  0);
Copy

출력

 -- Additional Params: --TablesTransformationTarget SnowflakeIceberg
CREATE OR REPLACE ICEBERG TABLE FINANCE.FINANCE_TABLE
  (
 customerName VARCHAR,
 accountBalance VARCHAR
  )
  CATALOG = 'SNOWFLAKE'
--  --** SSC-PRF-0010 - PARTITION BY REMOVED, AT LEAST ONE OF THE SPECIFIED EXPRESSIONS HAVE NO ICEBERG PARTITION TRANSFORM EQUIVALENT **
--  PARTITION BY CASE_N(
--  accountBalance <  0 ,
--  accountBalance >=  0)
  COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": {  "major": 1,  "minor": 0,  "patch": "0.0" }, "attributes": {  "component": "teradata",  "convertedOn": "12/16/2025",  "domain": "no-domain-provided",  "migrationid": "9CebAVkM33qsfTnTrMh3Dw==" }}'
;
Copy

모범 사례

  • Analyze the impact of partitioning in the performance of queries over the generated Iceberg tables, if the difference is neglible then this PRF can be safely ignored.

  • 추가 지원이 필요하면 snowconvert-support@Snowflake.com으로 문의해 주십시오.