This warning indicates that the statement uses cursor fetch bulk operations. These operations allow you to retrieve multiple rows of data from a cursor at once, instead of one row at a time. Using bulk operations improves performance by reducing the number of communications needed between the client and server.
This pattern can become complex if not implemented correctly. For example, retrieving too many rows in a single fetch operation can consume excessive memory. It’s crucial to maintain a balance between the number of rows fetched and the available memory resources.
Using collation in Snowflake can impact query performance, particularly in WHERE clauses. To learn more about how collation affects performance, please refer to the Performance Implications of Using Collation.
A warning has been generated to indicate that a column was created with case-insensitive collation. Using this column in queries may cause slower performance.
CREATETABLE 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"}}';
CREATEORREPLACETABLE 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"}}';
If your application’s performance is significantly affected by case-insensitive collation, consider rewriting your code to avoid using it. However, if the performance impact is acceptable, you can ignore this warning.
This warning appears when a FETCH statement is detected within a loop. The FETCH statement retrieves and processes individual rows from a result set one at a time.
Processing large datasets using cursors within loops can become complex, especially when:
Multiple table joins are involved
Complex calculations are required
Large numbers of rows need to be processed
This pattern may lead to performance issues and can be difficult to maintain as the data volume grows.
CREATEPROCEDURE oracle_fetch_inside_loop
IS
var1 table1.column1%TYPE;CURSOR cursor1 ISSELECT COLUMN_NAME FROM table1;BEGINWHILEtrueLOOPFETCH cursor1 INTO var1;EXITWHEN cursor1%NOTFOUND;ENDLOOP;END;
CREATEORREPLACEPROCEDURE oracle_fetch_inside_loop ()RETURNSVARCHARLANGUAGESQLCOMMENT='{ "origin": "sf_sc", "name": "snowconvert", "version": { "major": 0, "minor": 0, "patch": "0" }, "attributes": { "component": "oracle", "convertedOn": "07/02/2025", "domain": "no-domain-provided" }}'EXECUTEASCALLERAS$$
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;
$$;
CREATEORREPLACEPROCEDURE transact_fetch_inside_loop ()RETURNSVARCHARLANGUAGESQLCOMMENT='{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'EXECUTEASCALLERAS$$
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;
$$;
To improve performance and avoid complex patterns, use set-based operations instead of loops. Replace row-by-row processing with SQL statements (SELECT, UPDATE, DELETE) that operate on multiple rows simultaneously using WHERE clauses. This approach is more efficient and easier to maintain.
This warning indicates that the statement contains cursor for loops. A cursor for loop is a programming structure that processes query results one row at a time, allowing you to work with individual records from a result set.
This warning helps identify potential performance issues in cursor FOR loops. Performance problems may arise when:
The SELECT statement within the cursor returns a large dataset
The loop contains complex operations
The loop contains nested loops
While SnowConvert AI can detect these patterns, you should review and optimize the code to ensure efficient execution.
CREATEORREPLACEPROCEDURE oracle_cursor_for_loop ()RETURNSVARCHARLANGUAGESQLCOMMENT='{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'EXECUTEASCALLERAS$$
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;
$$;
This warning indicates that the statement contains nested cursors. A cursor is a database feature that lets you process rows from a query result one at a time. Nested cursors occur when you use one cursor inside another cursor’s loop, which can impact performance and should be used with caution.
Nested cursors can significantly slow down your code’s performance, particularly when working with large amounts of data. This is because each time a cursor operates, it needs to communicate with the database server, creating additional processing overhead and delays.
CREATEORALTERPROCEDURE procedureSample
ASBEGINDECLARE@outer_category_id INT,@outer_category_name NVARCHAR(50),@inner_product_name NVARCHAR(50);-- Define the outer cursorDECLARE outer_cursor CURSORFORSELECT category_id, category_name FROM categories;-- Open the outer cursorOPEN@outer_cursor;-- Fetch the first row from the outer cursorFETCHNEXTFROM outer_cursor INTO@outer_category_id,@outer_category_name;-- Start the outer loopWHILE@@FETCH_STATUS =0BEGIN
PRINT 'Category: '+@outer_category_name;-- Define the inner cursorDECLARE inner_cursor CURSORFORSELECT product_name FROM products WHERE category_id =@outer_category_id;-- Open the inner cursorOPEN inner_cursor;FETCHNEXTFROM inner_cursor INTO@inner_product_name;WHILE@@FETCH_STATUS =0BEGIN
PRINT 'Product: '+@inner_product_name +' Category: '+CAST(@outer_category_id AS NVARCHAR(10));-- Fetch the next row from the inner cursorFETCHNEXTFROM inner_cursor INTO@inner_product_name;END;-- Close the inner cursorCLOSE inner_cursor;
DEALLOCATE inner_cursor;-- Fetch the next row from the outer cursorFETCHNEXTFROM outer_cursor INTO@outer_category_id,@outer_category_name;END;-- Close the outer cursorCLOSE outer_cursor;
DEALLOCATE outer_cursor;END;
CREATEORREPLACEPROCEDURE procedureSample ()RETURNSVARCHARLANGUAGESQLCOMMENT='{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'EXECUTEASCALLERAS$$
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;
$$;
CREATEORREPLACEPROCEDURE procedureSample ()RETURNSVARCHARLANGUAGESQLCOMMENT='{ "origin": "sf_sc", "name": "snowconvert", "version": { "major": 0, "minor": 0, "patch": "0" }, "attributes": { "component": "oracle", "convertedOn": "07/02/2025", "domain": "no-domain-provided" }}'EXECUTEASCALLERAS$$
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;
$$;
CREATEORREPLACEPROCEDURE procedureSample ()RETURNSVARCHARLANGUAGESQLCOMMENT='{ "origin": "sf_sc", "name": "snowconvert", "version": { "major": 0, "minor": 0, "patch": "0" }, "attributes": { "component": "oracle", "convertedOn": "07/02/2025", "domain": "no-domain-provided" }}'EXECUTEASCALLERAS$$
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;
$$;
This message appears when a query contains a cursor definition. When a cursor expression is evaluated, it returns and automatically opens a nested cursor. For more details, see Oracle Cursor Expression.
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;
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;
CREATE MULTISET TABLE T_2008,
NO FALLBACK,
NO BEFORE JOURNAL,
NO AFTER JOURNAL,
CHECKSUM =DEFAULT,DEFAULT MERGEBLOCKRATIO
(
COL1 NUMBER(20,0)NOTNULL,
COL2 INTEGER,
COL3 VARCHAR(4)CHARACTERSET LATIN NOT CASESPECIFIC,
COL4 DATEFORMAT'YYYY-MM-DD')PRIMARYINDEX(
COL1, COL2
)PARTITIONBY( RANGE_N(COL4 BETWEENDATE'2010-01-01'ANDDATE'2025-12-31' EACH INTERVAL'1'YEAR),
CASE_N(
COL3 ='T',
COL3 ='M',
COL3 ='L'));-- PARTITION BY transformed to CLUSTER BY
This message appears when SnowConvert AI detects loop usage in procedural code. Loops such as LOOP, WHILE, and FOR can lead to row-by-row processing and may degrade performance in Snowflake, especially when the loop iterates over large datasets or contains complex logic. The message is informational and prompts a review of the pattern.
CREATEORREPLACEPROCEDURE loop_example ()RETURNSVARCHARLANGUAGESQLEXECUTEASCALLERAS$$
BEGIN
--** SSC-PRF-0008 - PERFORMANCE REVIEW - LOOP USAGE **
FOR i IN 1 TO 10
LOOP
NULL;
END LOOP;
END;
$$;;
This message appears when SnowConvert AI detects a cursor declaration in procedural code. Cursors allow row-by-row processing of query results, which can lead to performance issues in Snowflake, especially when processing large datasets.
While cursors are valid in Snowflake Scripting, they introduce overhead because:
Each row is processed individually rather than as a set
Multiple round trips to the database may be required
Memory usage can be higher compared to set-based operations
This warning is informational and prompts a review of whether the cursor usage is necessary or can be replaced with more efficient set-based operations.
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.
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.