سلام و عرض ادب خدمت دوستان عزیزم
امیدوارم حالتون خوب باشه
یکی از مواردی که در بررسی کدهای سازمانها و شرکتهای مختلف دیدم وجود داره استفاده از Scalar function ها هست. امروز میخوام نکته ای رو بگم که بهتون کمک میکنه پرفورمنس این نوع توابع نیز افزایش پیدا کنه.
اگر در تعریف این تابع دقت کرده باشین این کلید ها وجود داره
<function_option>::=
{
[ ENCRYPTION ]
| [ SCHEMABINDING ]
| [ RETURNS NULL ON NULL INPUT | CALLED ON NULL INPUT ]
| [ EXECUTE_AS_Clause ]
}
یکی از این گزینه ها Returns null on null input هست . اگر د راستفاده از این تابع در جدول مورد نظر مقادیر Null وجود داره که میتونه Null برگردونه ، با اضافه کردن این گزینه به هدر تابع ، اسکیوال سرور مقادیر Null رو صرفنظر کرده و فقط مقادیر اصلی رو به این تابع ارسال ، و خروجی واحد دریافت خواهد کرد.
مثلا فرض کنید در یک جدولی تابعی نوشتید که میدونید اگر مقدار Null به پارامتر تابع ارسال بشه حتما خروجی Null خواهد بود و این جدول فرضا 40000 ردیف دارد. که 20000 ردیف آن Null و مابقی مقدار دارد.
اگر از این دستور استفاده نکنید و از تابعی که نوشتید در بدنه Select استفاده کنید ، این تابع به ازای هر 40000 ردیف موجود در جدول اجرا خواهد شد. ولی اگر از این دستور استفاده کنید تابع شما فقط 20000 مرتبه اجرا خواهد شد و برای مقادیر Null اجرا نمی شود.
این سبب خواهد شد سرعت پردازش و اجرای کدهای Scalar شما در صورتی که دارای شرط فوق باشه ، افزایش پیدا کنه.
در ضمن اینکه این گزینه از نسخه 2008 به بعد وجود داره.
برای تست این موضوع ، بر روی دیتابیس Adventureworks 2017 نیز میتونید با توابع زیر این رو تست کنید.
USE [AdventureWorks2017];
GO
CREATE FUNCTION [dbo].[ufnLeadingZeros_new](
@Value int
)
RETURNS varchar(8)
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS
BEGIN
DECLARE @ReturnValue varchar(8);
SET @ReturnValue = CONVERT(varchar(8), @Value);
SET @ReturnValue = REPLICATE('0', 8 - DATALENGTH(@ReturnValue)) + @ReturnValue;
RETURN (@ReturnValue);
END;
GO
و سپس این کدهارو اجرا کنید.
SELECT SalesOrderID, dbo.ufnLeadingZeros(CurrencyRateID)
FROM Sales.SalesOrderHeader;
GO
SELECT SalesOrderID, dbo.ufnLeadingZeros_new(CurrencyRateID)
FROM Sales.SalesOrderHeader;
GO
برای مانیتور کردنش هم Event های زیر رو تعریف کنید.
CREATE EVENT SESSION [Session72] ON SERVER
ADD EVENT sqlserver.module_end(
WHERE ([package0].[equal_uint64]([sqlserver].[session_id],(125)))),
ADD EVENT sqlserver.sql_batch_completed(
WHERE ([package0].[equal_uint64]([sqlserver].[session_id],(125)))),
ADD EVENT sqlserver.sql_batch_starting(
WHERE ([package0].[equal_uint64]([sqlserver].[session_id],(125)))),
ADD EVENT sqlserver.sql_statement_completed(
WHERE ([package0].[equal_uint64]([sqlserver].[session_id],(125)))),
ADD EVENT sqlserver.sql_statement_starting(
WHERE ([package0].[equal_uint64]([sqlserver].[session_id],(125))))
WITH (TRACK_CAUSALITY=ON)
GO
فقط نکته اینکه مقدار 125 برای Session تستی من هست که فیلتر کنم که دقیقا همین کدهارو نمایش بده. شما اینرو براساس Session خودتون فیلتر کنید.
امیدوارم این نکته در افزایش سرعت کدهاتون کمکی بهتون بکنه.
ارادتمند شما
حمیدرضا صادقیان
ID:@Hamidreza_Sadeghian
Channel :@SQL_Server
#TSQL #Scalar_Funcion #UDF #Performance
امیدوارم حالتون خوب باشه
یکی از مواردی که در بررسی کدهای سازمانها و شرکتهای مختلف دیدم وجود داره استفاده از Scalar function ها هست. امروز میخوام نکته ای رو بگم که بهتون کمک میکنه پرفورمنس این نوع توابع نیز افزایش پیدا کنه.
اگر در تعریف این تابع دقت کرده باشین این کلید ها وجود داره
<function_option>::=
{
[ ENCRYPTION ]
| [ SCHEMABINDING ]
| [ RETURNS NULL ON NULL INPUT | CALLED ON NULL INPUT ]
| [ EXECUTE_AS_Clause ]
}
یکی از این گزینه ها Returns null on null input هست . اگر د راستفاده از این تابع در جدول مورد نظر مقادیر Null وجود داره که میتونه Null برگردونه ، با اضافه کردن این گزینه به هدر تابع ، اسکیوال سرور مقادیر Null رو صرفنظر کرده و فقط مقادیر اصلی رو به این تابع ارسال ، و خروجی واحد دریافت خواهد کرد.
مثلا فرض کنید در یک جدولی تابعی نوشتید که میدونید اگر مقدار Null به پارامتر تابع ارسال بشه حتما خروجی Null خواهد بود و این جدول فرضا 40000 ردیف دارد. که 20000 ردیف آن Null و مابقی مقدار دارد.
اگر از این دستور استفاده نکنید و از تابعی که نوشتید در بدنه Select استفاده کنید ، این تابع به ازای هر 40000 ردیف موجود در جدول اجرا خواهد شد. ولی اگر از این دستور استفاده کنید تابع شما فقط 20000 مرتبه اجرا خواهد شد و برای مقادیر Null اجرا نمی شود.
این سبب خواهد شد سرعت پردازش و اجرای کدهای Scalar شما در صورتی که دارای شرط فوق باشه ، افزایش پیدا کنه.
در ضمن اینکه این گزینه از نسخه 2008 به بعد وجود داره.
برای تست این موضوع ، بر روی دیتابیس Adventureworks 2017 نیز میتونید با توابع زیر این رو تست کنید.
USE [AdventureWorks2017];
GO
CREATE FUNCTION [dbo].[ufnLeadingZeros_new](
@Value int
)
RETURNS varchar(8)
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS
BEGIN
DECLARE @ReturnValue varchar(8);
SET @ReturnValue = CONVERT(varchar(8), @Value);
SET @ReturnValue = REPLICATE('0', 8 - DATALENGTH(@ReturnValue)) + @ReturnValue;
RETURN (@ReturnValue);
END;
GO
و سپس این کدهارو اجرا کنید.
SELECT SalesOrderID, dbo.ufnLeadingZeros(CurrencyRateID)
FROM Sales.SalesOrderHeader;
GO
SELECT SalesOrderID, dbo.ufnLeadingZeros_new(CurrencyRateID)
FROM Sales.SalesOrderHeader;
GO
برای مانیتور کردنش هم Event های زیر رو تعریف کنید.
CREATE EVENT SESSION [Session72] ON SERVER
ADD EVENT sqlserver.module_end(
WHERE ([package0].[equal_uint64]([sqlserver].[session_id],(125)))),
ADD EVENT sqlserver.sql_batch_completed(
WHERE ([package0].[equal_uint64]([sqlserver].[session_id],(125)))),
ADD EVENT sqlserver.sql_batch_starting(
WHERE ([package0].[equal_uint64]([sqlserver].[session_id],(125)))),
ADD EVENT sqlserver.sql_statement_completed(
WHERE ([package0].[equal_uint64]([sqlserver].[session_id],(125)))),
ADD EVENT sqlserver.sql_statement_starting(
WHERE ([package0].[equal_uint64]([sqlserver].[session_id],(125))))
WITH (TRACK_CAUSALITY=ON)
GO
فقط نکته اینکه مقدار 125 برای Session تستی من هست که فیلتر کنم که دقیقا همین کدهارو نمایش بده. شما اینرو براساس Session خودتون فیلتر کنید.
امیدوارم این نکته در افزایش سرعت کدهاتون کمکی بهتون بکنه.
ارادتمند شما
حمیدرضا صادقیان
ID:@Hamidreza_Sadeghian
Channel :@SQL_Server
#TSQL #Scalar_Funcion #UDF #Performance
دوره بسیار عالی با افرادی بسیار دقیق و باهوش در شرکت موتورسازان تراکتور سازی تبریز
#performance_tuning
#T_SQL
#SQL_Server
#performance_tuning
#T_SQL
#SQL_Server
👍1
سلام دوستان
🔍 یک چالش جالب در SQL Server که میتونست یک مجموعه رو زمینگیر کنه!
چند وقت پیش در یکی از مجموعهها با یک مشکل عجیب مواجه بودن 👀
سیستم از یک تعداد کاربر مشخص به بعد خطا میداد و اجازه نمیداد اتصال جدیدی به دیتابیس برقرار بشه.
🔎 بعد از دیدن خطا، اولین چیزی که به ذهنم رسید این بود:
احتمالاً تنظیمات user connections دستکاری شده.
مشکل اینجا بود که حتی اتصال عادی هم به دیتابیس برقرار نمیشد!
با کلی داستان و از طریق sqlcmd تونستم مستقیم به Engine وصل بشم 💪
📌 با بررسی تنظیمات:
'sp_configure 'user connections
مشخص شد مقدار روی 100 ست شده 😐
🔧 راهحل ساده ولی حیاتی بود:
مقدار user connections رو روی 0 گذاشتم
عدد 0 یعنی:
👉 SQL Server خودش مدیریت میکنه (تا حدود 32767 اتصال همزمان)
بعد از اعمال تغییر، مجبور شدیم یک بار سرویس SQL Server رو ریست کنیم 🔄
و… مشکل بهطور کامل حل شد ✅
✨ نکته جالبتر؟
کاربران میگفتن حتی سرعت سیستم هم بهتر شده!
احتمالاً سیستم مدام سعی میکرد اتصال بگیره، خطا میخورد و منتظر میموند تا دوباره تلاش کنه ⏳
🧠 جمعبندی مهم:
هر عددی که در SQL Server میبینید، معمولاً پشتش یک منطق و سناریو وجود داره.
این تنظیمات رو:
❌ با حدس
❌ با سلیقه
❌ یا «ببینیم با کدوم عدد حال میکنیم»
نباید تغییر داد!
⚠️ یک عدد اشتباه، خیلی راحت میتونه کل یک شرکت رو دچار اختلال کنه.
کمی دقت بیشتر در این جزئیات، هزینههای خیلی بزرگی رو کم میکنه.
#SQLServer #DBA #Performance #Troubleshooting #Database #Production #Experience
🔍 یک چالش جالب در SQL Server که میتونست یک مجموعه رو زمینگیر کنه!
چند وقت پیش در یکی از مجموعهها با یک مشکل عجیب مواجه بودن 👀
سیستم از یک تعداد کاربر مشخص به بعد خطا میداد و اجازه نمیداد اتصال جدیدی به دیتابیس برقرار بشه.
🔎 بعد از دیدن خطا، اولین چیزی که به ذهنم رسید این بود:
احتمالاً تنظیمات user connections دستکاری شده.
مشکل اینجا بود که حتی اتصال عادی هم به دیتابیس برقرار نمیشد!
با کلی داستان و از طریق sqlcmd تونستم مستقیم به Engine وصل بشم 💪
📌 با بررسی تنظیمات:
'sp_configure 'user connections
مشخص شد مقدار روی 100 ست شده 😐
🔧 راهحل ساده ولی حیاتی بود:
مقدار user connections رو روی 0 گذاشتم
عدد 0 یعنی:
👉 SQL Server خودش مدیریت میکنه (تا حدود 32767 اتصال همزمان)
بعد از اعمال تغییر، مجبور شدیم یک بار سرویس SQL Server رو ریست کنیم 🔄
و… مشکل بهطور کامل حل شد ✅
✨ نکته جالبتر؟
کاربران میگفتن حتی سرعت سیستم هم بهتر شده!
احتمالاً سیستم مدام سعی میکرد اتصال بگیره، خطا میخورد و منتظر میموند تا دوباره تلاش کنه ⏳
🧠 جمعبندی مهم:
هر عددی که در SQL Server میبینید، معمولاً پشتش یک منطق و سناریو وجود داره.
این تنظیمات رو:
❌ با حدس
❌ با سلیقه
❌ یا «ببینیم با کدوم عدد حال میکنیم»
نباید تغییر داد!
⚠️ یک عدد اشتباه، خیلی راحت میتونه کل یک شرکت رو دچار اختلال کنه.
کمی دقت بیشتر در این جزئیات، هزینههای خیلی بزرگی رو کم میکنه.
#SQLServer #DBA #Performance #Troubleshooting #Database #Production #Experience
❤22👍7👌2
سلام دوستان
📉 Shrink در SQL Server به روایت یک فضای کار اشتراکی!
فرض کن یکی میره یه فضای کار اشتراکی 🏢
اوایل کارش کوچیکه، یه میز اشتراکی میگیره.
کمکم کارش میگیره 📈، میگه «نه، من یه اتاق میخوام» 🚪
اتاق رو میگیره، کارش راه میافته، همه چی خوبه 😌
فرداش چی؟
میگه «نه بابا، الان اتاق زیادیه»
اتاق رو پس میده، برمیگرده میز اشتراکی 😐
عصر دوباره کار زیاد میشه:
«بچهها اتاق بدین!»
دوباره اتاق میگیره…
پس میده…
میگیره…
پس میده… 🤦♂️
حالا صاحب فضای کار اشتراکی کلافه نشده؟
دیوارها جابهجا نمیشن؟
نظم فضا به هم نمیریزه؟ 😵
📌 Shrink توی SQL Server دقیقاً همینه!
دیتابیس رشد میکنه 📊
شما Shrink میکنی چون «فضا خالیه»
دوباره دیتا میاد، دوباره رشد میکنه
دوباره Shrink
نتیجه؟
Fragmentation شدید 🧩
فشار بیخودی به IO 💥
بدتر شدن Performance 🐌
📢 Shrink یعنی پس گرفتن فضا، نه مدیریت فضا!
Shrink برای شرایط خاصه:
بعد از حذف دائمی حجم عظیمی از دیتا
وقتی مطمئنی دیگه به اون فضا نیاز نداری
نه برای اینکه:
❌ هر هفته دیسک خالی ببینی
❌ یا وجدان DBAت آروم بشه 😄
و این مساله هم برای فایل LDF صدق می کنه هم MDF.
بارها توی همه Job ها من Job برای Shrink دیدم و ایجاد Fragmentation بر روی LDF ها.
🎯 نتیجه:
به جای این همه «اتاق پس بده، اتاق بگیر»
یه فضای مناسب بگیر، درست استفاده کن،
و بگذار دیتابیس با آرامش رشد کنه
و برای کنترل LDF هم تهیه بکاپ منظم از Log ها به این مساله به شدت کمک می کنه.🧘♂️
hashtag#SQLServer hashtag#DBA hashtag#Shrink hashtag#Performance hashtag#DatabaseLife hashtag#طنز_فنی 😄
📉 Shrink در SQL Server به روایت یک فضای کار اشتراکی!
فرض کن یکی میره یه فضای کار اشتراکی 🏢
اوایل کارش کوچیکه، یه میز اشتراکی میگیره.
کمکم کارش میگیره 📈، میگه «نه، من یه اتاق میخوام» 🚪
اتاق رو میگیره، کارش راه میافته، همه چی خوبه 😌
فرداش چی؟
میگه «نه بابا، الان اتاق زیادیه»
اتاق رو پس میده، برمیگرده میز اشتراکی 😐
عصر دوباره کار زیاد میشه:
«بچهها اتاق بدین!»
دوباره اتاق میگیره…
پس میده…
میگیره…
پس میده… 🤦♂️
حالا صاحب فضای کار اشتراکی کلافه نشده؟
دیوارها جابهجا نمیشن؟
نظم فضا به هم نمیریزه؟ 😵
📌 Shrink توی SQL Server دقیقاً همینه!
دیتابیس رشد میکنه 📊
شما Shrink میکنی چون «فضا خالیه»
دوباره دیتا میاد، دوباره رشد میکنه
دوباره Shrink
نتیجه؟
Fragmentation شدید 🧩
فشار بیخودی به IO 💥
بدتر شدن Performance 🐌
📢 Shrink یعنی پس گرفتن فضا، نه مدیریت فضا!
Shrink برای شرایط خاصه:
بعد از حذف دائمی حجم عظیمی از دیتا
وقتی مطمئنی دیگه به اون فضا نیاز نداری
نه برای اینکه:
❌ هر هفته دیسک خالی ببینی
❌ یا وجدان DBAت آروم بشه 😄
و این مساله هم برای فایل LDF صدق می کنه هم MDF.
بارها توی همه Job ها من Job برای Shrink دیدم و ایجاد Fragmentation بر روی LDF ها.
🎯 نتیجه:
به جای این همه «اتاق پس بده، اتاق بگیر»
یه فضای مناسب بگیر، درست استفاده کن،
و بگذار دیتابیس با آرامش رشد کنه
و برای کنترل LDF هم تهیه بکاپ منظم از Log ها به این مساله به شدت کمک می کنه.🧘♂️
hashtag#SQLServer hashtag#DBA hashtag#Shrink hashtag#Performance hashtag#DatabaseLife hashtag#طنز_فنی 😄
👍16👌6🙏2🤨2❤1
تا حالا Running Total تو SQL Server نوشتی و با خیال راحت رد شدی؟ 😌
📌 معمولاً برای Running Total یه چیزی شبیه این مینویسیم:
همهچیز هم ظاهراً درسته…
اما دقیقاً همینجا مشکل شروع میشه 😐
🔍 مشکل کجاست؟
وقتی داخل OVER فقط ORDER BY مینویسیم و چیز دیگهای مشخص نمیکنیم،
خود SQL Server بهصورت پیشفرض از این استفاده میکنه 👇
و این یعنی چی؟ 🤔
یعنی اگر تو ستون ORDER BY (مثلاً OrderDate) مقدار تکراری وجود داشته باشه:
اونقوت SQL Server تمام ردیفهایی که تاریخ یکسان دارن رو «یک ردیف منطقی» در نظر میگیره
و Running Total برای همه اونها با هم محاسبه میشه
نتیجه؟
➕ جمع یههو میپره
😵💫 چیزی که حس میکنیم غلطه، ولی در واقع «غیرمنتظره» است
❗️ نکته مهم:
1- SQL Server اشتباه نکرده
2- ما ناخواسته رفتار RANGE رو فعال کردیم
🚀 راهحل درست و حرفهای:
اگه Running Total واقعی میخوای، یعنی ردیفبهردیف و بدون پرش،
باید صریح بنویسی:
یا حتی کوتاهتر:
✔️ محاسبه دقیق
✔️ بدون رفتار عجیب
✔️ بازدهی خیلی بهتر (In-Memory بهجای TempDB)
🧠 جمعبندی
همیشه Defaultها دوست ما نیستن
استفاده از RANGE فقط وقتی خوبه که عمداً بخوای Tieها یکی حساب بشن
برای ۹۹٪ سناریوهای Running Total → ROWS رو همیشه صریح بنویس
یه خط کداضافه ، ولی کلی تفاوت تو نتیجه و Performance 🔥
#SQLServer #TSQL #DBA #Performance #WindowFunctions #RunningTotal #DatabaseTips
📌 معمولاً برای Running Total یه چیزی شبیه این مینویسیم:
SUM(TotalDue) OVER (
PARTITION BY CustomerID
ORDER BY OrderDate
)
همهچیز هم ظاهراً درسته…
اما دقیقاً همینجا مشکل شروع میشه 😐
🔍 مشکل کجاست؟
وقتی داخل OVER فقط ORDER BY مینویسیم و چیز دیگهای مشخص نمیکنیم،
خود SQL Server بهصورت پیشفرض از این استفاده میکنه 👇
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
و این یعنی چی؟ 🤔
یعنی اگر تو ستون ORDER BY (مثلاً OrderDate) مقدار تکراری وجود داشته باشه:
اونقوت SQL Server تمام ردیفهایی که تاریخ یکسان دارن رو «یک ردیف منطقی» در نظر میگیره
و Running Total برای همه اونها با هم محاسبه میشه
نتیجه؟
➕ جمع یههو میپره
😵💫 چیزی که حس میکنیم غلطه، ولی در واقع «غیرمنتظره» است
❗️ نکته مهم:
1- SQL Server اشتباه نکرده
2- ما ناخواسته رفتار RANGE رو فعال کردیم
🚀 راهحل درست و حرفهای:
اگه Running Total واقعی میخوای، یعنی ردیفبهردیف و بدون پرش،
باید صریح بنویسی:
SUM(TotalDue) OVER (
PARTITION BY CustomerID
ORDER BY OrderDate
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
)
یا حتی کوتاهتر:
ROWS UNBOUNDED PRECEDING
✔️ محاسبه دقیق
✔️ بدون رفتار عجیب
✔️ بازدهی خیلی بهتر (In-Memory بهجای TempDB)
🧠 جمعبندی
همیشه Defaultها دوست ما نیستن
استفاده از RANGE فقط وقتی خوبه که عمداً بخوای Tieها یکی حساب بشن
برای ۹۹٪ سناریوهای Running Total → ROWS رو همیشه صریح بنویس
یه خط کداضافه ، ولی کلی تفاوت تو نتیجه و Performance 🔥
#SQLServer #TSQL #DBA #Performance #WindowFunctions #RunningTotal #DatabaseTips
👍14❤8🔥2