انواع تیبل ها
✅ Table Variable vs Temporary Table — تفاوت کامل
| ویژگی | Temporary Table (#Temp) | Table Variable (@TableVar) |
|---|---|---|
| محل ذخیرهسازی | در TempDB ایجاد میشود | در TempDB ایجاد میشود (برخلاف تصور برخی که فکر میکنند در حافظه است!) |
| قابلیت ایجاد Index | میتوان Index تعریف کرد | فقط Primary Key یا Unique Constraint قابل ایجاد است |
| پشتیبانی از Statistics (آمار داده) | دارد ✅ → باعث بهینه بودن Query Plan میشود | ندارد ❌ → ممکن است باعث کندی شود |
| قلمرو (Scope) | تا پایان Connection یا تا وقتی DROP شود | فقط داخل همان Batch یا Stored Procedure |
| مناسب برای حجم داده زیاد؟ | بله ✅ | خیر ❌ (کند میشود) |
| Transaction Behavior | تحت تأثیر Transaction و Rollback قرار میگیرد ✅ | خارج از Rollback باقی میماند ❌ |
امکان استفاده با SELECT INTO | بله ✅ | خیر ❌ (باید صراحتاً تعریف شود) |
🎯 در چه مواقعی از کدام استفاده کنیم؟
✅ از Temporary Table (#Temp) استفاده کن وقتی:
- حجم داده زیاد است
- نیاز به Index یا Statistics برای بهینهسازی داری
- میخواهی چندبار روی آن عملیات انجام دهی (Join, Update, Delete)
✅ از Table Variable (@TableVar) استفاده کن وقتی:
- حجم داده کم است
- فقط یک بار استفاده میشود
- داخل Function یا Stored Procedure کوچک استفاده میکنی
🧪 مثال مقایسه عملکرد
-- Temporary Table
CREATE TABLE #Temp (ID INT, Name NVARCHAR(50));
INSERT INTO #Temp VALUES (1, 'Ali'), (2, 'Sara');
SELECT * FROM #Temp;
-- Table Variable
DECLARE @TableVar TABLE (ID INT, Name NVARCHAR(50));
INSERT INTO @TableVar VALUES (1, 'Ali'), (2, 'Sara');
SELECT * FROM @TableVar;
ظاهر یکی است، اما از نظر Performance و Behavior کاملاً فرق دارند.
🧠 جمعبندی استادانه
| اگر… | انتخاب مناسب |
|---|---|
| داده کم است و فقط استفاده سریع لازم داری | @TableVar (Table Variable) |
| داده زیاد است، میخواهی Join / Index بزنی | #Temp (Temporary Table) |
| داخل Transaction کار میکنی و میخواهی Rollback شود | #Temp |
| داخل Function هستی | فقط @TableVar قابل استفاده است |
✅ تفاوت Table Variable / Temporary Table با Indexed View
| ویژگی | Temporary Table (#Temp) | Table Variable (@TableVar) | Indexed View (WITH SCHEMABINDING + INDEX) |
|---|---|---|---|
| نوع | جدول موقتی | جدول موقتی در محدوده Batch | View دائمی + ایندکس ذخیرهشده |
| محل ذخیره | TempDB | TempDB | پایگاه داده اصلی (نه TempDB) |
| زمان ایجاد | در زمان اجرا | در زمان اجرا | یکبار ساخته میشود و همیشه پابرجاست |
| قابلیت ایجاد ایندکس | دستی | محدود (فقط PK/Unique) | ایندکس خوشهای دائم دارد |
| Lifetime | موقتی (تا پایان Connection یا Scope) | فقط داخل همان Batch | دائمی مثل یک جدول |
| مناسب برای Join و عملیات پیچیده؟ | بله | برای دیتا کم | عالی مخصوصاً در Queryهای تکراری |
| مناسب برای ذخیره Result Set موقت؟ | بله | برای دیتا کم | خیر (برای این کار طراحی نشده) |
| بهینهسازی عملکرد Queryهای تکراری | معمولی | ضعیفتر | عالی ✅ |
🎯 Indexed View دقیقاً چیست؟
یک View معمولی فقط یک Query ذخیره شدهست. ولی Indexed View وقتی Index داشته باشد، نتیجهاش به صورت فیزیکی (Materialized) ذخیره میگردد. یعنی مثل یک جدول واقعی رفتار میکند و هر بار Query اجرا نمیشود.
مثال واقعی:
CREATE VIEW dbo.vw_SalesSummary
WITH SCHEMABINDING
AS
SELECT CustomerID, SUM(TotalAmount) AS TotalSales
FROM dbo.Sales
GROUP BY CustomerID;
GO
CREATE UNIQUE CLUSTERED INDEX IX_vw_SalesSummary
ON dbo.vw_SalesSummary (CustomerID);
✅ حالا هر وقت Query بزنیم:
SELECT * FROM dbo.vw_SalesSummary WHERE CustomerID = 10;
SQL Server سراغ دیتاهای آماده در ایندکس میرود → سرعت بسیار بالا!
🧠 پس فرق اصلی Indexed View با Temp Table / Table Variable چیست؟
| اگر هدف تو نگهداری موقت داده در وسط یک Query یا Procedure است → از Temp Table یا Table Variable استفاده کن. |
| اگر هدف تو بهینهسازی یک Query سنگین و تکراری است → از Indexed View استفاده کن. |
📌 جمعبندی استادانه
| نیاز | انتخاب مناسب |
|---|---|
| ذخیره موقت داده داخل Procedure | #Temp یا @TableVar |
| سرعت بیشتر در Queryهای تکراری و محاسبات Aggregation | Indexed View |
| ایندکسگذاری سنگین و Join زیاد | #Temp بهتر از @TableVar |
| کاهش لود CPU در گزارشگیری | Indexed View بهترین گزینه است |
اگر خواستی، میتونم:
- Indexed View را با Table Comparison Benchmark بزنم
- یا سناریو طراحی کنم که Indexed View باعث ۱۰ برابر سریعتر شدن Query بشود
✅ تفاوت Table Variable / Temporary Table با Indexed View
| ویژگی | Temporary Table (#Temp) | Table Variable (@TableVar) | Indexed View (WITH SCHEMABINDING + INDEX) |
|---|---|---|---|
| نوع | جدول موقتی | جدول موقتی در محدوده Batch | View دائمی + ایندکس ذخیرهشده |
| محل ذخیره | TempDB | TempDB | پایگاه داده اصلی (نه TempDB) |
| زمان ایجاد | در زمان اجرا | در زمان اجرا | یکبار ساخته میشود و همیشه پابرجاست |
| قابلیت ایجاد ایندکس | دستی | محدود (فقط PK/Unique) | ایندکس خوشهای دائم دارد |
| Lifetime | موقتی (تا پایان Connection یا Scope) | فقط داخل همان Batch | دائمی مثل یک جدول |
| مناسب برای Join و عملیات پیچیده؟ | بله | برای دیتا کم | عالی مخصوصاً در Queryهای تکراری |
| مناسب برای ذخیره Result Set موقت؟ | بله | برای دیتا کم | خیر (برای این کار طراحی نشده) |
| بهینهسازی عملکرد Queryهای تکراری | معمولی | ضعیفتر | عالی ✅ |
🎯 Indexed View دقیقاً چیست؟
یک View معمولی فقط یک Query ذخیره شدهست. ولی Indexed View وقتی Index داشته باشد، نتیجهاش به صورت فیزیکی (Materialized) ذخیره میگردد. یعنی مثل یک جدول واقعی رفتار میکند و هر بار Query اجرا نمیشود.
مثال واقعی:
CREATE VIEW dbo.vw_SalesSummary
WITH SCHEMABINDING
AS
SELECT CustomerID, SUM(TotalAmount) AS TotalSales
FROM dbo.Sales
GROUP BY CustomerID;
GO
CREATE UNIQUE CLUSTERED INDEX IX_vw_SalesSummary
ON dbo.vw_SalesSummary (CustomerID);
✅ حالا هر وقت Query بزنیم:
SELECT * FROM dbo.vw_SalesSummary WHERE CustomerID = 10;
SQL Server سراغ دیتاهای آماده در ایندکس میرود → سرعت بسیار بالا!
🧠 پس فرق اصلی Indexed View با Temp Table / Table Variable چیست؟
| اگر هدف تو نگهداری موقت داده در وسط یک Query یا Procedure است → از Temp Table یا Table Variable استفاده کن. |
| اگر هدف تو بهینهسازی یک Query سنگین و تکراری است → از Indexed View استفاده کن. |
📌 جمعبندی استادانه
| نیاز | انتخاب مناسب |
|---|---|
| ذخیره موقت داده داخل Procedure | #Temp یا @TableVar |
| سرعت بیشتر در Queryهای تکراری و محاسبات Aggregation | Indexed View |
| ایندکسگذاری سنگین و Join زیاد | #Temp بهتر از @TableVar |
| کاهش لود CPU در گزارشگیری | Indexed View بهترین گزینه است |
✅ مثال کاربردی ۱ — استفاده از Temporary Table برای ذخیره نتیجهٔ میانی
📌 سناریو:
فرض کن میخوای لیست مشتریانی که بیش از ۵ سفارش داشتهاند را پیدا کنی، ولی قبل از فیلتر کردن، میخواهی جزییات سفارشات را پردازش و گروهبندی کنی.
-- مرحله 1: ساخت Temp Table
CREATE TABLE #CustomerOrders (
CustomerID INT,
TotalOrders INT
);
-- مرحله 2: پر کردن دادهها
INSERT INTO #CustomerOrders
SELECT CustomerID, COUNT(*)
FROM Orders
GROUP BY CustomerID;
-- مرحله 3: استفاده از دادههای موقت
SELECT C.CustomerName, T.TotalOrders
FROM #CustomerOrders T
JOIN Customers C ON T.CustomerID = C.CustomerID
WHERE T.TotalOrders > 5;
🔎 Trace و رفتار این Query:
| مرحله | کار انجامشده | قفل (Lock) | تاثیر روی Query Plan |
|---|---|---|---|
| ساخت #Temp | ذخیره روی TempDB | Schema Lock | ✅ Optimizer میتواند Index روی آن بسازد |
| Insert | Bulk Insert | Row Lock | ✅ Statistics تولید میشود |
| Select Join | Full Join | Shared Lock | ✅ Execution Plan از Index استفاده میکند |
نتیجه: برای دیتای زیاد عالی است، چون Statistics دارد و SQL Server میتواند Plan بهینه بسازد.
✅ مثال کاربردی ۲ — استفاده از Table Variable برای نگه داشتن مقدار کم
📌 سناریو:
میخواهیم لیست ۳ محصول پرفروش را موقتاً نگه داریم و از آن در شرط دیگری استفاده کنیم.
DECLARE @TopProducts TABLE (
ProductID INT,
TotalSales INT
);
INSERT INTO @TopProducts
SELECT TOP 3 ProductID, SUM(Quantity)
FROM OrderDetails
GROUP BY ProductID
ORDER BY SUM(Quantity) DESC;
-- استفاده از آن در یک شرط دیگر
SELECT * FROM Products
WHERE ProductID IN (SELECT ProductID FROM @TopProducts);
🔎 Trace رفتار Table Variable:
| مرحله | رفتار | نکته |
|---|---|---|
| ساخت @TableVar | در TempDB ساخته میشود اما Statistics ندارد | ❌ Optimizer نمیداند چند ردیف دارد |
| Insert | سریع برای دیتا کم | ✅ مناسب برای کمتر از 100 ردیف |
| Select | Scan کامل | ❌ ممکن است Join ها سنگین شوند |
✅ نتیجهگیری استادانه
| اگر حجم داده زیاد است یا نیاز به Join و Index داری → از #Temp Table استفاده کن.
| اگر حجم داده کم و کنترلی است یا داخل Function یا Procedure کوچک هستی → از @Table Variable استفاده کن.
انواع جدولها / ساختارهای داده در SQL Server (برای مقایسه با Temp & Table Variable)
| نوع جدول / ساختار | دوام (Persistence) | محل ذخیره | Scope / محدوده | کاربرد اصلی | قابل مقایسه با Temp؟ |
|---|---|---|---|---|---|
| Permanent Table (جدول دائمی) | دائم | Database اصلی | Public | ذخیره اصلی داده | پایه مقایسه |
| Temporary Table (#Temp) | موقت | TempDB | Session یا Procedure | پردازش دادههای موقتی سنگین | ✅ |
| Global Temp Table (##Temp) | موقت | TempDB | کل سرور (تا پایان آخرین Session) | اشتراک موقتی بین Sessionها | ✅ |
| Table Variable (@Table) | موقت | TempDB | فقط Batch | دادههای کم و سبک | ✅ |
| Common Table Expression (CTE) | غیر مادی (Logical فقط) | حافظه | فقط همان Query | خوانایی و بازنویسی | ✅ به شکل محدود |
| Derived Table (Subquery in FROM) | غیر مادی | حافظه | داخل همان Query | جایگزین سریع و ساده | مشابه CTE |
| Indexed View (Materialized View) | دائم | Database اصلی | عمومی | بهینهسازی Queryهای تکراری | ✅ |
| Memory-Optimized Table (In-Memory OLTP) | دائم یا موقت | RAM | Public | سرعت بسیار بالا برای OLTP | ✅ برای مقایسه Performance |
| Temp Table in Memory (Table Variable + MEMORY_OPTIMIZED=ON) | موقت | RAM | Batch | نسخه پرسرعت Table Variable | ✅ |
مزایای temp table در stored procedure
وقتی شما داخل یک Stored Procedure از Temp Table استفاده میکنید، ممکنه سرعت رو بهطور قابل توجهی افزایش بده. دلایل اصلی:
1. شکستن Queryهای پیچیده به بخشهای کوچکتر
- وقتی یک کوئری خیلی پیچیده با چندین
JOIN،SUBQUERYیاCTEداری، SQL Server باید یک execution plan خیلی سنگین بسازه. - اگر نتایج میانی رو در یک Temp Table ذخیره کنی، SQL Server اون مرحله رو جداگانه محاسبه میکنه و برای مراحل بعدی با یک دیتاست آماده ادامه میده.
- این باعث میشه Plan سادهتر و بهینهتر بشه.
2. ایجاد ایندکس روی دادههای موقت
- روی CTE یا Derived Table نمیتونی ایندکس بسازی.
- اما روی یک Temp Table میتونی Clustered/Non-Clustered Index تعریف کنی.
- این کار باعث میشه
JOIN,WHERE,GROUP BYسریعتر بشه.
3. کاهش تکرار محاسبات
فرض کن داخل SP یک محاسبه سنگین (مثلاً روی میلیونها ردیف) چند بار نیاز داری.
- اگر از CTE استفاده کنی، هر بار مجدداً محاسبه میشه.
- ولی اگر خروجی رو یک بار در Temp Table بذاری، دفعههای بعد مستقیم از همون جدول خونده میشه.
4. کاهش فشار روی Transaction Log اصلی
- Temp Table در tempdb ساخته میشه، نه در دیتابیس اصلی.
- این یعنی تراکنشهای موقت به Log دیتابیس اصلی اضافه نمیشن → کمتر شدن لاگ نویسی → سریعتر شدن عملیات.
5. بهبود موازیسازی و حافظه
- گاهی اوقات Query Optimizer نمیتونه بهینهترین Execution Plan رو برای یک کوئری خیلی بزرگ انتخاب کنه.
- شکستن کار با Temp Table باعث میشه SQL Server بهتر بتونه حافظه رو مدیریت کنه و پردازش موازی انجام بده.
✅ نتیجه:
Temp Table سرعت Stored Procedure رو بالا میبره چون:
- نتایج میانی رو ذخیره میکنه.
- امکان ایندکسگذاری روی دادههای موقت رو فراهم میکنه.
- از محاسبات تکراری جلوگیری میکنه.
- فشار روی Transaction Log اصلی رو کم میکنه