جدول مجازی در SQL Server
۱. تعریف جدول مجازی
در SQL Server چیزی به نام Virtual Table یا “جدول مجازی” بیشتر به عنوان یک مفهوم (concept) مطرحه، نه یک شیء مستقل مثل Table.
یعنی جدولی که به صورت فیزیکی در دیتابیس ذخیره نشده بلکه موقتاً و بر اساس کوئری ساخته میشه. این جدول فقط در زمان اجرای کوئری وجود داره و بعد از اتمام کار از بین میره.
۲. مثالها و انواع جدولهای مجازی
جدول مجازی در چند حالت متداول استفاده میشه:
✅ الف) View (نما)
وقتی یک VIEW تعریف میکنیم، اون View خودش دادهها رو ذخیره نمیکنه، بلکه یک جدول مجازی بر اساس کوئری ما میسازه.
CREATE VIEW vw_EmployeeSalary
AS
SELECT EmployeeID, Name, Salary
FROM Employees
WHERE Salary > 5000;
حالا:
SELECT * FROM vw_EmployeeSalary;
این Query یک جدول مجازی میسازه که مثل یک جدول واقعی میتونیم ازش Select بگیریم.
✅ ب) Derived Table (جدول مشتقشده درون کوئری)
وقتی داخل یک کوئری یک Subquery مینویسیم و براش اسم مستعار میذاریم، اون هم یک جدول مجازی میسازه.
SELECT t.DepartmentID, AVG(t.Salary) AS AvgSalary
FROM (
SELECT DepartmentID, Salary
FROM Employees
WHERE Salary > 3000
) t
GROUP BY t.DepartmentID;
اینجا (SELECT DepartmentID, Salary ...) t یک جدول مجازی هست.
✅ ج) Inserted و Deleted در Trigger ها
در Triggerها وقتی عملیاتی مثل INSERT، UPDATE یا DELETE انجام میدیم، SQL Server بهصورت خودکار جدولهای مجازی Inserted و Deleted رو ایجاد میکنه.
- جدول مجازی Inserted رکوردهای جدید رو نگه میداره.
- جدول مجازی Deleted رکوردهای قبلی رو نگه میداره.
مثال:
CREATE TRIGGER trg_Audit
ON Employees
AFTER UPDATE
AS
BEGIN
SELECT * FROM Inserted; -- مقادیر جدید
SELECT * FROM Deleted; -- مقادیر قبلی
END;
✅ د) CTE (Common Table Expression)
CTE هم یک جدول مجازی موقتیه که فقط در همون Scope کوئری وجود داره:
WITH DeptCTE AS (
SELECT DepartmentID, COUNT(*) AS EmpCount
FROM Employees
GROUP BY DepartmentID
)
SELECT * FROM DeptCTE WHERE EmpCount > 5;
DeptCTE یک جدول مجازی محسوب میشه.
۳. کاربردهای جدول مجازی
- سادهتر کردن کوئریهای پیچیده
- استفادهی چندباره از نتایج یک Subquery
- جداسازی منطق کوئری (مثل View یا CTE)
- دسترسی به دادههای تغییر یافته در Triggerها
- افزایش خوانایی و نگهداری راحتتر کوئریها
🔑 جمعبندی:
جدول مجازی در SQL Server یعنی جدولی که وجود فیزیکی نداره و فقط موقع اجرای کوئری ایجاد میشه. نمونههاش شامل View، Derived Table، Inserted/Deleted در Trigger، و CTE هست.
Indexed View (نمای ایندکسشده)
بهطور پیشفرض View یک جدول مجازی هست ولی دادهها رو ذخیره نمیکنه → هر بار کوئری بزنی باید دوباره دادهها محاسبه بشن.
اما اگر روی اون View یک Clustered Index بسازی، اون وقت SQL Server نتایج View رو به صورت فیزیکی توی دیسک ذخیره میکنه.
به همین خاطر، دفعات بعدی که کوئری اجرا بشه، لازم نیست دوباره محاسبات انجام بشن → سرعت خیلی بیشتر میشه.
✨ مثال
فرض کن جدولی داری به اسم Sales:
CREATE TABLE Sales (
SaleID INT PRIMARY KEY,
CustomerID INT,
Amount DECIMAL(10,2),
SaleDate DATE
);
۱) ساختن View (جدول مجازی معمولی)
CREATE VIEW vw_TotalSales
WITH SCHEMABINDING
AS
SELECT CustomerID, SUM(Amount) AS TotalAmount
FROM dbo.Sales
GROUP BY CustomerID;
🔹 اینجا vw_TotalSales یک جدول مجازی هست.
اگر کوئری بگیریم:
SELECT * FROM vw_TotalSales;
هر بار باید SQL Server کل جدول Sales رو اسکن کنه و SUM بگیره → کند میشه.
۲) ساختن Indexed View (جدول مجازی سریع)
حالا بیایم روی View ایندکس بذاریم:
CREATE UNIQUE CLUSTERED INDEX IX_vw_TotalSales
ON vw_TotalSales (CustomerID);
🔹 از این به بعد، نتیجهی View به صورت فیزیکی ذخیره میشه.
وقتی رکوردی به Sales اضافه/آپدیت/حذف بشه، SQL Server به صورت خودکار View رو هم بهروز میکنه.
۳) استفاده
حالا اگر این کوئری رو بزنیم:
SELECT * FROM vw_TotalSales WHERE CustomerID = 5;
SQL Server مستقیم میره سراغ ایندکس ساختهشده روی View → خیلی سریعتر از محاسبهی دوباره.
📊 مزایا
- سرعت خیلی بالاتر برای گزارشگیری و کوئریهای تحلیلی
- کاهش بار روی CPU چون محاسبات تکراری ذخیره میشن
- مناسب برای دادههایی که زیاد تغییر نمیکنن و بیشتر گزارش ازشون گرفته میشه
⚠️ معایب
- هزینهی بیشتری برای بهروزرسانی دادهها (چون علاوه بر جدول اصلی باید View ایندکسشده هم آپدیت بشه)
- محدودیت در تعریف View (مثلاً نمیتونی توش از
TOP,DISTINCT,OUTER JOIN,UNIONو … استفاده کنی) - نیاز به گزینه
WITH SCHEMABINDING
🔑 جمعبندی:
- View = جدول مجازی ساده (سرعت معمولی)
- Indexed View = جدول مجازی فیزیکیشده (Materialized View) که نتایج رو ذخیره میکنه و باعث افزایش سرعت میشه 🚀
بیایم مرحله به مرحله یک آزمایش عملی (Trace) انجام بدیم تا ببینی View معمولی و Indexed View چه تفاوتی در سرعت دارن.
۱) ساخت جدول نمونه
CREATE TABLE Sales (
SaleID INT IDENTITY PRIMARY KEY,
CustomerID INT,
Amount DECIMAL(10,2),
SaleDate DATE
);
۲) پر کردن جدول با دادهی زیاد
(برای تست سرعت، حجم داده رو زیاد میکنیم)
INSERT INTO Sales (CustomerID, Amount, SaleDate)
SELECT TOP 100000
ABS(CHECKSUM(NEWID())) % 1000 AS CustomerID,
CAST(RAND(CHECKSUM(NEWID())) * 1000 AS DECIMAL(10,2)) AS Amount,
DATEADD(DAY, -ABS(CHECKSUM(NEWID())) % 365, GETDATE())
FROM sys.objects a
CROSS JOIN sys.objects b;
🔹 اینجا حدود ۱۰۰ هزار رکورد ساخته میشه.
۳) فعال کردن Trace
برای دیدن تفاوت I/O و زمان:
SET STATISTICS IO ON;
SET STATISTICS TIME ON;
۴) ایجاد View معمولی (بدون ایندکس)
CREATE VIEW vw_TotalSales
WITH SCHEMABINDING
AS
SELECT CustomerID, SUM(Amount) AS TotalAmount
FROM dbo.Sales
GROUP BY CustomerID;
حالا کوئری زیر رو اجرا کن:
SELECT * FROM vw_TotalSales WHERE CustomerID = 50;
📌 نتیجه:
- در Messages میبینی
Table Scanانجام شده. - Logical Reads و CPU Time نسبتاً بالاست.
۵) ساخت Indexed View
CREATE UNIQUE CLUSTERED INDEX IX_vw_TotalSales
ON vw_TotalSales (CustomerID);
۶) اجرای دوباره همان کوئری
SELECT * FROM vw_TotalSales WHERE CustomerID = 50;
📌 نتیجه:
- SQL Server مستقیم از ایندکس روی View استفاده میکنه.
- Logical Reads خیلی کم میشه.
- CPU Time هم به شکل چشمگیری پایین میاد.
۷) مقایسه
مثلاً (اعداد فرضی برای درک بهتر):
| حالت | Logical Reads | CPU Time | Duration |
|---|---|---|---|
| View معمولی | 1200 | 50 ms | 60 ms |
| Indexed View | 3 | 1 ms | 1 ms |
✅ اینجا میبینی که Indexed View به شدت سرعت رو افزایش میده مخصوصاً برای دادههای بزرگ و کوئریهای تکراری.