SnowConvert AI - Messages généraux d’examen des performances¶
SSC-PRF-0001¶
Cette instruction utilise des opérations de récupération en masse de curseurs.
Description¶
Cet avertissement indique que l’instruction utilise des opérations d’extraction en bloc du curseur. Ces opérations vous permettent de récupérer plusieurs lignes de données d’un curseur en même temps, au lieu d’une ligne à la fois. L’utilisation d’opérations en bloc améliore les performances en réduisant le nombre de communications nécessaires entre le client et le serveur.
Ce modèle peut devenir complexe s’il n’est pas mis en œuvre correctement. Par exemple, récupérer un trop grand nombre de lignes lors d’une seule opération de récupération peut entraîner une consommation excessive de mémoire. Il est essentiel de maintenir un équilibre entre le nombre de lignes extraites et les ressources mémoire disponibles.
Exemple de code¶
Oracle¶
Entrée¶
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;
Sortie¶
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;
$$;
Meilleures pratiques¶
Pour une assistance supplémentaire, veuillez nous contacter à l’adresse suivante : snowconvert-support@snowflake.com
SSC-PRF-0002¶
Les colonnes insensibles à la casse peuvent réduire les performances des requêtes.
Description¶
L’utilisation du classement dans Snowflake peut avoir un impact sur les performances des requêtes, en particulier dans les clauses WHERE. Pour en savoir plus sur la manière dont le classement affecte les performances, veuillez vous référer à la section Implications de l’utilisation du classement sur les performances.
Un avertissement a été généré pour indiquer qu’une colonne a été créée avec un classement insensible à la casse. L’utilisation de cette colonne dans les requêtes peut ralentir les performances.
Exemples de code :¶
Sortie¶
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"}}'
;
Oracle¶
Entrée¶
CREATE TABLE exampleTable (
col1 VARCHAR(50) COLLATE BINARY_CI,
col2 VARCHAR(50) COLLATE BINARY_CS
);
Sortie¶
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"}}'
;
Microsoft SQL Server¶
Entrée¶
CREATE TABLE exampleTable (
col1 VARCHAR(50) COLLATE Latin1_General_CI_AS,
col2 VARCHAR(50) COLLATE Latin1_General_CS_AS
);
Sortie¶
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"}}'
;
Meilleures pratiques¶
Si les performances de votre application sont considérablement affectées par le classement insensible à la casse, envisagez de réécrire votre code pour ne pas l’utiliser. Toutefois, si l’impact sur les performances est acceptable, vous pouvez ignorer cet avertissement.
Pour toute assistance supplémentaire, contactez-nous à l’adresse suivante : snowconvert-support@snowflake.com
SSC-PRF-0003¶
La récupération dans une boucle est considérée comme un modèle complexe, susceptible de dégrader les performances de Snowflake.
Gravité¶
Faible
Description¶
Cet avertissement apparaît lorsqu’une instruction FETCH est détectée dans une boucle. L’instruction FETCH récupère et traite une à une les lignes d’un jeu de résultats.
Le traitement de grands ensembles de données à l’aide de curseurs dans des boucles peut devenir complexe, en particulier lorsque :
Des jointures de tables multiples sont impliquées
Des calculs complexes sont exigés
Un grand nombre de lignes doit être traité
Ce modèle peut entraîner des problèmes de performance et peut être difficile à maintenir au fur et à mesure que le volume de données augmente.
Exemple de code¶
Teradata¶
Entrée¶
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;
Sortie¶
--** 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;
$$;
Oracle¶
Entrée¶
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;
Sortie¶
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;
$$;
SQL Server¶
Entrée¶
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;
Sortie¶
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;
$$;
Meilleures pratiques¶
Pour améliorer les performances et éviter les modèles complexes, utilisez des opérations basées sur des ensembles plutôt que des boucles. Remplacez le traitement ligne par ligne par des instructions SQL (SELECT, UPDATE, DELETE) qui opèrent simultanément sur plusieurs lignes à l’aide de clauses WHERE. Cette approche est plus efficace et plus facile à maintenir.
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;
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;
$$;
Les opérations basées sur les ensembles peuvent être utilisées pour traiter les données plus efficacement.
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;
Les opérations basées sur les ensembles peuvent être utilisées pour traiter les données plus efficacement.
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;
$$;
Meilleures pratiques¶
Pour une assistance supplémentaire, veuillez nous contacter à l’adresse suivante : snowconvert-support@snowflake.com
SSC-PRF-0004¶
Cette instruction utilise un curseur For Loop.
Gravité¶
Aucun(e)
Description¶
Cet avertissement indique que l’instruction contient un curseur For loops. Une boucle de curseur est une structure de programmation qui traite les résultats d’une requête une ligne à la fois, ce qui vous permet de travailler avec des enregistrements individuels d’un jeu de résultats.
Cet avertissement permet d’identifier les problèmes de performance potentiels dans les boucles FOR du curseur. Des problèmes de performance peuvent survenir dans les cas suivants :
L’instruction SELECT au sein du curseur renvoie un grand ensemble de données
La boucle contient des opérations complexes
La boucle contient des boucles imbriquées
Si SnowConvert AI peut détecter ces modèles, vous devez examiner et optimiser le code pour garantir une exécution efficace.
Exemple de code¶
Teradata¶
Entrée¶
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;
Sortie¶
--** 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;
$$;
Oracle¶
Entrée¶
CREATE OR REPLACE PROCEDURE oracle_cursor_for_loop AS
BEGIN
FOR r1 IN (SELECT col1 FROM sample_table) LOOP
NULL;
END LOOP;
END;
Sortie¶
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;
$$;
Meilleures pratiques¶
Pour une assistance supplémentaire, veuillez nous contacter à l’adresse suivante : snowconvert-support@snowflake.com
SSC-PRF-0005¶
L’instruction ci-dessous utilise des curseurs imbriqués.
Note
Pour une meilleure lisibilité, nous avons simplifié certaines sections du code dans cet exemple.
Gravité¶
Aucun(e)
Description¶
Cet avertissement indique que l’instruction contient des curseurs imbriqués. Un curseur est une fonction de base de données qui vous permet de traiter les lignes d’un résultat de requête une par une. On parle de curseurs imbriqués lorsque vous utilisez un curseur à l’intérieur de la boucle d’un autre curseur, ce qui peut avoir un impact sur les performances et doit être utilisé avec prudence.
Les curseurs imbriqués peuvent ralentir considérablement les performances de votre code, en particulier lorsque vous travaillez avec de grandes quantités de données. En effet, à chaque opération, le curseur doit communiquer avec le serveur de la base de données, ce qui entraîne des frais généraux et des retards supplémentaires.
Exemples de code :¶
SQL Server¶
Entrée¶
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;
Sortie¶
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;
$$;
Oracle¶
Curseur explicite¶
Entrée¶
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;
Sortie¶
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;
$$;
Curseur implicite¶
Entrée¶
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;
Sortie¶
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;
$$;
Meilleures pratiques¶
Les curseurs imbriqués doivent être évités car ils peuvent avoir un impact négatif sur les performances et rendre le code plus complexe.
Au lieu de curseurs imbriqués, utilisez les fonctions SQL, telles que :
Fonctions SQL
Jointures
Sous-requêtes
Fonctions de fenêtre
Expressions de table communes (CTEs)
Requêtes récursives Ces alternatives traitent les données en masse et sont plus efficaces.
Pour toute assistance supplémentaire, contactez-nous à l’adresse suivante : snowconvert-support@snowflake.com
SSC-PRF-0006¶
Le curseur imbriqué à l’intérieur de la requête n’est pas pris en charge dans Snowflake.
Gravité¶
Aucun(e)
Description¶
Ce message apparaît lorsqu’une requête contient une définition de curseur. Lorsqu’une expression de curseur est évaluée, elle renvoie et ouvre automatiquement un curseur imbriqué. Pour plus de détails, voir Oracle Cursor Expression.
Exemples de code :¶
Entrée¶
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;
Sortie¶
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;
Meilleures pratiques¶
Nous vous recommandons d’éviter les curseurs, car ils peuvent nuire aux performances et rendre le code plus complexe.
Au lieu d’utiliser des curseurs imbriqués, envisagez les alternatives suivantes :
Fonctions SQL
Jointures
Sous-requêtes
Fonctions de fenêtre
Expressions de table communes (CTEs)
Requêtes récursives Ces options sont plus adaptées au traitement efficace de grandes quantités de données.
Pour toute assistance supplémentaire, contactez-nous à l’adresse suivante : snowconvert-support@snowflake.com
SSC-PRF-0007¶
PERFORMANCE REVIEW - CLUSTER BY
Description¶
Signale les cas où l’utilisation de CLUSTER BY peut entraîner des problèmes de performances.
Exemple de code¶
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
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
Transigez :¶
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)
);
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" }}'
;
Meilleures pratiques¶
Examinez le code afin d’identifier d’éventuels problèmes de performances. Vous trouverez plus d’informations à ce sujet ici.
Si vous avez besoin de plus d’assistance, vous pouvez nous envoyer un e-mail à snowconvert-support@snowflake.com.