فُكَّ شيفرة الخطة التي يختارها فعليًا مُخطِّط SQLite لاستعلاماتك باستخدام EXPLAIN QUERY PLAN.
افتح هذا الدرس في Kodokonإن لغة SQL تصريحية: فأنت تصف النتيجة، لا كيفية الحصول عليها. ومُخطِّط الاستعلام هو الذي يقرّر كيفية قراءة البيانات. ولمراقبته وهو يعمل، توفّر SQLite أمرين: يعطي EXPLAIN QUERY PLAN خطة عالية المستوى قابلة للقراءة، بينما يُفرِغ EXPLAIN وحده الشيفرة الثنائية (bytecode) للآلة الافتراضية VDBE. ثبِّت أداة سطر الأوامر sqlite3، أو افتح sqliteonline.com في متصفحك، وأعِد تنفيذ كل مثال يلي.
CREATE TABLE departments (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL
);
CREATE TABLE employees (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
department_id INTEGER,
salary INTEGER NOT NULL
);
INSERT INTO departments (id, name) VALUES
(1, 'Engineering'),
(2, 'Sales');
INSERT INTO employees
(id, name, department_id, salary)
VALUES
(1, 'Ada', 1, 65000),
(2, 'Grace', 1, 72000),
(3, 'Alan', 2, 58000);ضع EXPLAIN QUERY PLAN أمام أيّ استعلام SELECT. يصف كل سطر من النتيجة كيفية قراءة جدول ما. وتهيمن كلمتان مفتاحيتان: تعني SCAN أن الجدول يُمسَح بالكامل، صفًّا صفًّا، في حين تشير SEARCH إلى وصول موجَّه يقوده فهرس. فبدون فهرس مناسب، حتى المساواة البسيطة تُطلِق مسحًا كاملًا.
EXPLAIN QUERY PLAN
SELECT * FROM employees
WHERE department_id = 1;
-- Result: SCAN employees
-- (no index: the whole table is read)أنشئ فهرسًا على العمود المُرشَّح، ثم أعد تنفيذ الاستعلام نفسه تمامًا: تنتقل الخطة من SCAN إلى SEARCH ... USING INDEX. وهناك إشارات أخرى قيّمة أيضًا: يكشف USE TEMP B-TREE عن فرز أو تجميع مُجسَّد في الذاكرة (وهو غالبًا علامة على غياب فهرس للترتيب)، ويشير USING COVERING INDEX إلى أن الجدول لم يُفتَح أصلًا.
CREATE INDEX idx_emp_dept
ON employees (department_id);
EXPLAIN QUERY PLAN
SELECT * FROM employees
WHERE department_id = 1;
-- SEARCH employees USING INDEX
-- idx_emp_dept (department_id=?)EXPLAIN QUERY PLAN مقارنةً بـ EXPLAIN وحده؟SCAN employees؟ANALYZE؟sqlite_stat1 لتوجيه المُخطِّط