SQL Academy · Pelajaran

Mengelakkan Gelung Tanpa Henti

Had kedalaman dan pengesanan kitaran.

Pelajaran 4 daripada 413 langkah

Mengelakkan Gelung Tanpa Henti ialah pelajaran SQL Academy percuma di CoddyKit. Ini ialah pelajaran 4 daripada 4. Anda boleh membaca keseluruhan pelajaran di bawah secara percuma — kemudian berlatih secara praktikal dalam pelayar menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7. Pelajaran ini merupakan sebahagian daripada laluan pembelajaran SQL Academy, dan kemajuan anda disegerakkan merentas web serta aplikasi CoddyKit. Kursus SQL Academy merangkumi sejumlah 4 pelajaran.

Masalah Gelung Tak Terhingga

CTE rekursif sangat berkuasa, tetapi mempunyai risiko serius: jika pertanyaan anda tidak pernah mencapai kes asas, pertanyaan itu akan berulang selama-lamanya, menggunakan semua memori yang tersedia dan menyebabkan sesi pangkalan data terhenti.

Memahami sebab gelung tak terhingga berlaku ialah langkah pertama untuk mencegahnya.

Bilakah Gelung Tidak Berakhir?

CTE rekursif berulang tanpa henti apabila istilah rekursif terus menghasilkan baris baharu tanpa pernah mencapai keadaan yang tidak menghasilkan baris baharu.

Hal ini biasanya berlaku dalam dua keadaan: syarat penamatan tiada atau salah, atau data berkitar apabila nod A menunjuk kepada B dan B menunjuk kembali kepada A.

-- Simple recursive CTE that WOULD loop forever
-- (do NOT run this as-is; illustration only)
WITH RECURSIVE counter AS (
  SELECT 1 AS n          -- base case
  UNION ALL
  SELECT n + 1           -- recursive term
  FROM counter
  -- no WHERE clause to stop it!
)
SELECT n FROM counter;

Menambah Had Kedalaman

Perlindungan paling mudah ialah pengira kedalaman. Tambahkan lajur yang meningkat sebanyak 1 pada setiap langkah rekursif, kemudian berhenti apabila nilainya melebihi kedalaman maksimum.

Ini menjamin penamatan tanpa mengira data, manakala had yang dipilih memberikan had keselamatan.

WITH RECURSIVE counter AS (
  SELECT 1 AS n
  UNION ALL
  SELECT n + 1
  FROM counter
  WHERE n < 10       -- stop at depth 10
)
SELECT n FROM counter;

Had Kedalaman dalam Pertanyaan Hierarki

Semasa menelusuri hierarki pekerja, anda boleh menjejaki kedalaman bersama laluan. Klausa WHERE depth < 5 menghalang penelusuran melebihi 5 aras walaupun data mempunyai pautan yang lebih dalam atau berbentuk kitaran.

CREATE TEMP TABLE employees (
  id   INT PRIMARY KEY,
  name TEXT,
  manager_id INT
);

INSERT INTO employees VALUES
  (1, 'Alice', NULL),
  (2, 'Bob',   1),
  (3, 'Carol', 2),
  (4, 'Dave',  3);

WITH RECURSIVE hierarchy AS (
  SELECT id, name, manager_id, 1 AS depth
  FROM employees
  WHERE manager_id IS NULL          -- root

  UNION ALL

  SELECT e.id, e.name, e.manager_id, h.depth + 1
  FROM employees e
  JOIN hierarchy h ON e.manager_id = h.id
  WHERE h.depth < 5                 -- depth limit
)
SELECT id, name, depth FROM hierarchy ORDER BY depth, id;

Apakah Pengesanan Kitaran?

Kitaran berlaku dalam data graf apabila mengikuti sisi akhirnya membawa kembali kepada nod yang telah anda lawati. Contohnya: A → B → C → A.

Had kedalaman masih menamatkan pertanyaan dalam data berkitar, tetapi tidak memberitahu anda di mana kitaran itu berlaku. Pengesanan kitaran secara jelas dapat berbuat demikian.

CREATE TEMP TABLE edges (
  from_node INT,
  to_node   INT
);

-- Introduce a cycle: 1->2->3->1
INSERT INTO edges VALUES
  (1, 2),
  (2, 3),
  (3, 1),   -- cycle back to 1
  (1, 4);   -- also a non-cyclic branch

SELECT * FROM edges;

Menjejaki Nod yang Telah Dilawati dengan Tatasusunan

Teknik pengesanan kitaran yang kukuh ialah membawa tatasusunan ID nod yang telah dilawati sepanjang rekursi. Sebelum melawati nod seterusnya, semak sama ada nod itu sudah terdapat dalam tatasusunan. Jika ya, langkau nod tersebut.

PostgreSQL memudahkan perkara ini dengan operator ANY(array) dan operator penambahan tatasusunan ||.

WITH RECURSIVE traverse AS (
  -- Start from node 1
  SELECT from_node,
         to_node,
         ARRAY[from_node] AS visited
  FROM edges
  WHERE from_node = 1

  UNION ALL

  SELECT e.from_node,
         e.to_node,
         t.visited || e.from_node
  FROM edges e
  JOIN traverse t ON e.from_node = t.to_node
  WHERE NOT (e.from_node = ANY(t.visited))   -- skip visited nodes
)
SELECT from_node, to_node, visited
FROM traverse;

Klausa CYCLE (PostgreSQL 14+)

PostgreSQL 14 memperkenalkan klausa CYCLE terbina dalam untuk CTE rekursif. Klausa ini menambah dua lajur secara automatik: penanda benar/palsu yang bernilai true apabila kitaran dikesan, dan tatasusunan yang merekodkan laluan yang dilalui.

Ini lebih kemas daripada menyelenggara tatasusunan secara manual.

WITH RECURSIVE traverse AS (
  SELECT from_node, to_node
  FROM edges
  WHERE from_node = 1

  UNION ALL

  SELECT e.from_node, e.to_node
  FROM edges e
  JOIN traverse t ON e.from_node = t.to_node
)
CYCLE from_node SET is_cycle USING path
SELECT from_node, to_node, is_cycle, path
FROM traverse;

Menggabungkan Had Kedalaman dan Pengesanan Kitaran

Menggunakan had kedalaman dan pengesanan kitaran bersama-sama memberikan jaminan keselamatan yang paling kukuh:

  • Had kedalaman bertindak sebagai had maksimum mutlak tanpa mengira kualiti data.
  • Pengesanan kitaran berhenti dengan segera apabila gelung ditemui, sekali gus menjimatkan lelaran yang tidak diperlukan.

Dalam pertanyaan persekitaran pengeluaran, sentiasa gunakan sekurang-kurangnya satu daripada perlindungan ini.

WITH RECURSIVE traverse AS (
  SELECT from_node,
         to_node,
         1 AS depth,
         ARRAY[from_node] AS visited
  FROM edges
  WHERE from_node = 1

  UNION ALL

  SELECT e.from_node,
         e.to_node,
         t.depth + 1,
         t.visited || e.from_node
  FROM edges e
  JOIN traverse t ON e.from_node = t.to_node
  WHERE t.depth < 10                           -- depth limit
    AND NOT (e.from_node = ANY(t.visited))     -- cycle guard
)
SELECT from_node, to_node, depth, visited
FROM traverse;

Membina Laluan Penuh sebagai Rentetan

Bersama-sama pengesanan kitaran, adalah berguna untuk merekodkan laluan penelusuran penuh sebagai rentetan yang mudah dibaca manusia. Menggabungkan ID nod yang dipisahkan oleh -> memudahkan paparan atau penyahpepijatan laluan yang diambil melalui graf.

WITH RECURSIVE traverse AS (
  SELECT from_node,
         to_node,
         1 AS depth,
         ARRAY[from_node] AS visited,
         from_node::TEXT AS path_str
  FROM edges
  WHERE from_node = 1

  UNION ALL

  SELECT e.from_node,
         e.to_node,
         t.depth + 1,
         t.visited || e.from_node,
         t.path_str || ' -> ' || e.from_node::TEXT
  FROM edges e
  JOIN traverse t ON e.from_node = t.to_node
  WHERE t.depth < 10
    AND NOT (e.from_node = ANY(t.visited))
)
SELECT from_node, to_node, path_str, depth
FROM traverse
ORDER BY depth;

Menetapkan max_recursive_iterations

Sesetengah pangkalan data (MariaDB, MySQL versi lama) menggunakan pemboleh ubah sesi untuk mengehadkan rekursi. Dalam PostgreSQL, pendekatan yang setara ialah bergantung pada pengira kedalaman yang anda tulis sendiri atau menggunakan had masa tamat pernyataan.

Menetapkan statement_timeout ialah perlindungan pilihan terakhir yang menamatkan sebarang pertanyaan yang tidak terkawal selepas tempoh tertentu.

-- PostgreSQL: set a statement timeout as a safety net
SET statement_timeout = '5s';

-- Now any query that runs longer than 5 seconds is cancelled
WITH RECURSIVE counter AS (
  SELECT 1 AS n
  UNION ALL
  SELECT n + 1 FROM counter WHERE n < 1000000
)
SELECT MAX(n) FROM counter;

-- Reset to default when done
SET statement_timeout = '0';

Memilih Had Kedalaman yang Tepat

Tiada had kedalaman yang sesuai untuk semua keadaan. Pilih had berdasarkan kedalaman maksimum yang munasabah dalam data anda:

  • Carta organisasi jarang melebihi 10-15 aras — gunakan depth < 20 sebagai lebihan yang selesa.
  • Pepohon sistem fail mungkin mencapai kedalaman 50-100 aras.
  • Penelusuran graf rangkaian sosial sering dihadkan kepada 3-6 lompatan.

Tetapkan had yang cukup tinggi untuk merangkumi data yang sah, tetapi cukup rendah untuk mengesan pertanyaan yang tidak terkawal lebih awal.

-- Example: org chart with a generous but safe depth cap
WITH RECURSIVE org AS (
  SELECT id, name, manager_id, 1 AS depth
  FROM employees
  WHERE manager_id IS NULL

  UNION ALL

  SELECT e.id, e.name, e.manager_id, o.depth + 1
  FROM employees e
  JOIN org o ON e.manager_id = o.id
  WHERE o.depth < 20    -- realistic upper bound for an org chart
)
SELECT id, name, depth
FROM org
ORDER BY depth, name;

Had Kedalaman berbanding Pengesanan Kitaran

Teknik yang manakah patut digunakan?

Ulang Kaji: Memastikan Pertanyaan Rekursif Selamat

Berikut ialah ringkasan perkara yang telah anda pelajari tentang mengelakkan gelung tak terhingga dalam CTE rekursif:

  • Had kedalaman — tambahkan lajur pengira dan berhenti dengan WHERE depth < N. Sentiasa berkesan dan mudah dilaksanakan.
  • Pengesanan kitaran berasaskan tatasusunan — bawa ID nod yang telah dilawati dalam tatasusunan dan langkau mana-mana nod yang sudah terdapat di dalamnya. Berhenti lebih awal apabila kitaran pertama ditemui.
  • Klausa CYCLE (PostgreSQL 14+) — sintaks terbina dalam yang mengautomasikan penjejakan kitaran dengan lajur is_cycle dan path.
  • statement_timeout — perlindungan pada peringkat pangkalan data untuk pertanyaan yang tidak terkawal, bukan pengganti bagi logik yang betul.
  • Gabungkan kedua-duanya — gunakan had kedalaman dan pengesanan kitaran dalam persekitaran pengeluaran untuk mendapatkan jaminan paling kukuh.

Dengan teknik ini, anda boleh menelusuri hierarki dan graf dengan yakin tanpa risiko menyebabkan pangkalan data terhenti.

Percuma untuk bermula

Pelajari SQL dengan tutor kecerdasan buatan — percuma

Tulis dan jalankan kod sebenar dalam pelayar anda, dapatkan bantuan segera daripada tutor kecerdasan buatan yang tersedia 24/7, dan sambung semula dari tempat anda berhenti di web atau dalam aplikasi.

Kursus
46
Pelajaran
183

Soalan Lazim

Adakah pelajaran “Mengelakkan Gelung Tanpa Henti” percuma?

Ya — teks penuh “Mengelakkan Gelung Tanpa Henti” boleh dibaca secara percuma di web ini. Untuk berlatih secara interaktif menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7, serta membuka kunci baki kursus SQL Academy, tingkat taraf kepada CoddyKit PRO. Kursus SQL Academy merangkumi sejumlah 4 pelajaran.

Apakah yang akan saya pelajari dalam “Mengelakkan Gelung Tanpa Henti”?

Had kedalaman dan pengesanan kitaran. Anda berlatih SQL Academy menggunakan kod praktikal yang dijalankan terus dalam pelayar, manakala tutor kecerdasan buatan 24/7 menjawab soalan anda semasa anda mengikuti pelajaran.

Adakah saya memerlukan pengalaman untuk memulakan SQL Academy?

Tiada pengalaman terdahulu diperlukan. Pembelajaran SQL Academy di CoddyKit disusun untuk pelajar daripada peringkat pemula hingga lanjutan, jadi anda boleh bermula di sini atau dari awal dan belajar mengikut kadar anda sendiri. Ini ialah pelajaran 4 daripada 4.

Berapa lamakah pelajaran “Mengelakkan Gelung Tanpa Henti” diambil?

Kebanyakan pelajaran CoddyKit mengambil masa kira-kira 5–10 minit. Setiap pelajaran ringkas dan interaktif, jadi anda boleh membuat kemajuan secara berterusan dan menyambung tepat dari tempat anda berhenti di web atau aplikasi.

Bolehkah saya menulis dan menjalankan kod dalam pelajaran SQL Academy ini?

Ya. Setiap pelajaran SQL Academy menyertakan penyunting kod terbina dalam, jadi anda boleh menulis dan menjalankan kod sebenar terus dalam pelayar serta menerima maklum balas kecerdasan buatan serta-merta — tanpa memerlukan persediaan setempat.

Semua pelajaran dalam kursus ini

  1. Cara CTE Rekursif Berfungsi
  2. Menelusuri Pepohon Kategori
  3. Menjana Siri dan Urutan
  4. Mengelakkan Gelung Tanpa Henti
← Kembali ke SQL Academy