آموزش جامع متغیر سیستمی @@TOTAL_READ در SQL Server با ۱۰ مثال عملی
عیبیابی SQL Server معمولاً از یک پرسش ساده آغاز میشود: این شناسه، تنظیم یا شمارنده دقیقاً به کدام جزء موتور اشاره دارد؟ در این مقاله، @@TOTAL_READ از سطح مقدماتی تا سناریوهای حرفهای بررسی میشود و هر مثال با خروجی نمونه ارائه شده است.
با Deltaگیری دورهای میتوان شدت کلی Read I/O را پایش کرد و تغییر رفتار Workload را دید. تمرکز آموزش بر این است که @@TOTAL_READ در چه Contextی اجرا شود، نتیجه آن چگونه تفسیر شود و چه زمانی باید از یک DMV یا کاتالوگویوی جایگزین کمک گرفت.
برای مشاهده جایگاه @@TOTAL_READ میان سایر توابع و شمارندهها، راهنمای جامع توابع کمکی کارایی و Metadata در SQL Server را نیز مطالعه کنید.
تعریف و کاربرد اصلی @@TOTAL_READ
متغیر @@TOTAL_READ تعداد عملیات خواندن دیسک انجامشده توسط SQL Server را از آخرین Startup بهصورت تجمعی گزارش میکند. این تعریف در ظاهر کوتاه است، اما استفاده درست از @@TOTAL_READ به درک مفاهیمی مانند disk reads، physical I/O و cumulative counter وابسته است.
قاعده عملی @@TOTAL_READ: ابتدا ورودی و Context را معتبر کنید، سپس خروجی را با نوع داده و معنای واقعی آن تفسیر کنید.
Syntax تابع یا متغیر @@TOTAL_READ
SELECT @@TOTAL_READ AS Result;
پارامترهای @@TOTAL_READ
| پارامتر | توضیح |
|---|
| بدون پارامتر | شمارنده تجمعی Readهای دیسک Instance. |
نوع خروجی و رفتار NULL در @@TOTAL_READ
integer تجمعی. در کد تولیدی بهتر است نوع مقصد بهصورت صریح تعیین شود؛ زیرا تبدیل ضمنی میتواند مقایسه، مرتبسازی یا ذخیره نتیجه @@TOTAL_READ را مبهم کند.
مفاهیم کلیدی مرتبط با @@TOTAL_READ
- disk reads
- physical I/O
- cumulative counter در مبحث @@TOTAL_READ
- snapshot delta در مبحث @@TOTAL_READ
- buffer cache
- workload
- baseline در مبحث @@TOTAL_READ
تصویر نخست، ارتباط @@TOTAL_READ را با مفاهیم اختصاصی disk reads، physical I/O، cumulative counter و snapshot delta نشان میدهد؛ این روابط مبنای انتخاب ورودی و تفسیر خروجی هستند.
سناریوهای واقعی استفاده از @@TOTAL_READ
سناریوی 1 برای @@TOTAL_READ، «Baseline Read» است. در این حالت باید نتیجه همراه Context پایگاه داده، زمان نمونهبرداری و در صورت نیاز شناسه نشست ثبت شود تا داده برای عیبیابی بعدی ارزش داشته باشد.
سناریوی 2 برای @@TOTAL_READ، «مقایسه قبل و بعد از Deployment» است. در این حالت باید نتیجه همراه Context پایگاه داده، زمان نمونهبرداری و در صورت نیاز شناسه نشست ثبت شود تا داده برای عیبیابی بعدی ارزش داشته باشد.
سناریوی 3 برای @@TOTAL_READ، «تحلیل Batch Job» است. در این حالت باید نتیجه همراه Context پایگاه داده، زمان نمونهبرداری و در صورت نیاز شناسه نشست ثبت شود تا داده برای عیبیابی بعدی ارزش داشته باشد.
سناریوی 4 برای @@TOTAL_READ، «پایش شبانه» است. در این حالت باید نتیجه همراه Context پایگاه داده، زمان نمونهبرداری و در صورت نیاز شناسه نشست ثبت شود تا داده برای عیبیابی بعدی ارزش داشته باشد.
مثالهای عملی @@TOTAL_READ از ساده تا حرفهای
مثال 1: خواندن مقدار پایه @@TOTAL_READ
شمارنده خواندنهای دیسک را در لحظه فعلی میخوانیم. این سناریو بهطور اختصاصی برای درک رفتار @@TOTAL_READ طراحی شده است.
SELECT @@TOTAL_READ AS CurrentValue;
مقدار @@TOTAL_READ تجمعی است و بهتنهایی نرخ مصرف را نشان نمیدهد. هنگام استفاده سازمانی از @@TOTAL_READ، خروجی نمونه را با داده واقعی محیط خود تطبیق دهید.
مثال 2: ثبت Snapshot زماندار @@TOTAL_READ
مقدار خواندنهای دیسک را همراه زمان نمونهبرداری ثبت میکنیم. این سناریو بهطور اختصاصی برای درک رفتار @@TOTAL_READ طراحی شده است.
SELECT @@TOTAL_READ AS CounterValue,
SYSDATETIME() AS CapturedAt,
sqlserver_start_time
FROM sys.dm_os_sys_info;
| CounterValue | CapturedAt | sqlserver_start_time |
|---|
| 884200 | 2026-07-25 00:45:00 | 2026-07-20 08:00:00 |
زمان Startup مشخص میکند Baseline از چه نقطهای آغاز شده است. هنگام استفاده سازمانی از @@TOTAL_READ، خروجی نمونه را با داده واقعی محیط خود تطبیق دهید.
مثال 3: محاسبه اختلاف دو نمونه @@TOTAL_READ
برای خواندنهای دیسک دو Snapshot میگیریم و Delta را محاسبه میکنیم. این سناریو بهطور اختصاصی برای درک رفتار @@TOTAL_READ طراحی شده است.
DECLARE @Before bigint = CONVERT(bigint, @@TOTAL_READ);
WAITFOR DELAY '00:00:01';
DECLARE @After bigint = CONVERT(bigint, @@TOTAL_READ);
SELECT @Before AS BeforeValue,
@After AS AfterValue,
@After - @Before AS DeltaValue;
| BeforeValue | AfterValue | DeltaValue |
|---|
| 884200 | 884238 | 38 |
Delta @@TOTAL_READ برای بازه مشخص قابل تفسیرتر از مقدار مطلق است. هنگام استفاده سازمانی از @@TOTAL_READ، خروجی نمونه را با داده واقعی محیط خود تطبیق دهید.
مثال 4: ذخیره @@TOTAL_READ در جدول موقت
برای پایش خواندنهای دیسک یک جدول Snapshot کوچک میسازیم. این سناریو بهطور اختصاصی برای درک رفتار @@TOTAL_READ طراحی شده است.
CREATE TABLE #CounterSnapshot
(
CounterName sysname NOT NULL,
CounterValue bigint NOT NULL,
CapturedAt datetime2(3) NOT NULL
);
INSERT INTO #CounterSnapshot
VALUES (N'@@TOTAL_READ', CONVERT(bigint, @@TOTAL_READ), SYSDATETIME());
SELECT * FROM #CounterSnapshot;
| CounterName | CounterValue | CapturedAt |
|---|
| @@TOTAL_READ | 884200 | 2026-07-25 00:46:00.000 |
ذخیره تاریخچه امکان محاسبه نرخ و تشخیص تغییر Baseline را فراهم میکند. هنگام استفاده سازمانی از @@TOTAL_READ، خروجی نمونه را با داده واقعی محیط خود تطبیق دهید.
تصویر دوم، جریان اجرای @@TOTAL_READ را از ورودی و اعتبارسنجی تا تولید خروجی نمایش میدهد و نشان میدهد که buffer cache در کدام مرحله باید کنترل شود.
ادامه مثالهای پیشرفته @@TOTAL_READ
مثال 5: محاسبه نرخ @@TOTAL_READ
Delta شمارنده خواندنهای دیسک را بر ثانیه تقسیم میکنیم. در این مثال، هدف تنها اجرای Query نیست؛ بلکه نشان دادن یک تصمیم فنی صحیح پیرامون @@TOTAL_READ است.
DECLARE @StartValue bigint = CONVERT(bigint, @@TOTAL_READ);
DECLARE @StartTime datetime2(3) = SYSDATETIME();
WAITFOR DELAY '00:00:02';
DECLARE @EndValue bigint = CONVERT(bigint, @@TOTAL_READ);
DECLARE @Seconds decimal(18,3) =
DATEDIFF_BIG(millisecond, @StartTime, SYSDATETIME()) / 1000.0;
SELECT (@EndValue - @StartValue) / NULLIF(@Seconds, 0) AS EventsPerSecond;
نرخ @@TOTAL_READ برای مقایسه بازههای هماندازه مناسبتر است. این نکته از تفسیر سطحی یا استفاده تکراری و بیهدف از @@TOTAL_READ جلوگیری میکند.
مثال 6: کنترل کاهش غیرمنتظره @@TOTAL_READ
Restart یا Wraparound را با مقایسه دو مقدار تشخیص میدهیم. در این مثال، هدف تنها اجرای Query نیست؛ بلکه نشان دادن یک تصمیم فنی صحیح پیرامون @@TOTAL_READ است.
DECLARE @Previous bigint = 884300;
DECLARE @Current bigint = CONVERT(bigint, @@TOTAL_READ);
SELECT CASE
WHEN @Current < @Previous THEN N'Baseline بازنشانی یا شمارنده چرخیده است'
ELSE N'Delta معتبر است'
END AS CounterState;
| CounterState |
|---|
| Baseline بازنشانی یا شمارنده چرخیده است |
در صورت کاهش، Delta منفی را بهعنوان فعالیت واقعی ثبت نکنید. این نکته از تفسیر سطحی یا استفاده تکراری و بیهدف از @@TOTAL_READ جلوگیری میکند.
مثال 7: مدیریت بازه صفر برای @@TOTAL_READ
در محاسبه نرخ خواندنهای دیسک از تقسیم بر صفر جلوگیری میکنیم. در این مثال، هدف تنها اجرای Query نیست؛ بلکه نشان دادن یک تصمیم فنی صحیح پیرامون @@TOTAL_READ است.
DECLARE @Delta bigint = 38;
DECLARE @ElapsedSeconds decimal(18,3) = 0;
SELECT @Delta / NULLIF(@ElapsedSeconds, 0) AS SafeRate;
NULLIF خطای تقسیم بر صفر را حذف میکند و نیاز به Snapshot معتبر را نشان میدهد. این نکته از تفسیر سطحی یا استفاده تکراری و بیهدف از @@TOTAL_READ جلوگیری میکند.
مثال 8: مقایسه @@TOTAL_READ با @@TOTAL_WRITE
برای تفسیر بهتر خواندنهای دیسک یک شاخص مکمل را کنار آن میآوریم. در این مثال، هدف تنها اجرای Query نیست؛ بلکه نشان دادن یک تصمیم فنی صحیح پیرامون @@TOTAL_READ است.
SELECT CONVERT(bigint, @@TOTAL_READ) AS PrimaryCounter,
CONVERT(bigint, @@TOTAL_WRITE) AS CompanionCounter,
SYSDATETIME() AS CapturedAt;
| PrimaryCounter | CompanionCounter | CapturedAt |
|---|
| 884200 | 392100 | 2026-07-25 00:47:00 |
همبستگی دو شمارنده فقط سرنخ است و علت قطعی خواندنهای دیسک را اثبات نمیکند. این نکته از تفسیر سطحی یا استفاده تکراری و بیهدف از @@TOTAL_READ جلوگیری میکند.
مثال 9: روش اشتباه در تفسیر @@TOTAL_READ
بهجای قضاوت بر اساس عدد مطلق خواندنهای دیسک، Context زمانی را اضافه میکنیم. در این مثال، هدف تنها اجرای Query نیست؛ بلکه نشان دادن یک تصمیم فنی صحیح پیرامون @@TOTAL_READ است.
SELECT CONVERT(bigint, @@TOTAL_READ) AS AbsoluteValue,
DATEDIFF_BIG(second, sqlserver_start_time, SYSDATETIME()) AS UptimeSeconds
FROM sys.dm_os_sys_info;
| AbsoluteValue | UptimeSeconds |
|---|
| 884200 | 414300 |
دو سرور با Uptime متفاوت را نباید فقط با مقدار تجمعی مقایسه کرد. این نکته از تفسیر سطحی یا استفاده تکراری و بیهدف از @@TOTAL_READ جلوگیری میکند.
مثال 10: Snapshot کمهزینه @@TOTAL_READ
برای خواندنهای دیسک تنها ستونهای ضروری را در نمونهبرداری دورهای میخوانیم. در این مثال، هدف تنها اجرای Query نیست؛ بلکه نشان دادن یک تصمیم فنی صحیح پیرامون @@TOTAL_READ است.
SELECT
CONVERT(bigint, @@TOTAL_READ) AS CounterValue,
sqlserver_start_time,
SYSUTCDATETIME() AS CapturedAtUtc
FROM sys.dm_os_sys_info;
| CounterValue | sqlserver_start_time | CapturedAtUtc |
|---|
| 884200 | 2026-07-20 08:00:00 | 2026-07-24 21:18:00 |
Query سبک است، اما Frequency جمعآوری و نگهداری تاریخچه باید منطقی باشد. این نکته از تفسیر سطحی یا استفاده تکراری و بیهدف از @@TOTAL_READ جلوگیری میکند.
خطاهای رایج در کار با @@TOTAL_READ
خطای 1 در استفاده از @@TOTAL_READ
این مقدار Logical Read هر Query نیست. برای رفع این مشکل، ورودی و Context را از منبع معتبر بخوانید و نتیجه @@TOTAL_READ را پیش از ادامه منطق با شرط صریح کنترل کنید.
خطای 2 در استفاده از @@TOTAL_READ
Cache Hit میتواند بدون افزایش متناظر Physical Read به Query پاسخ دهد. برای رفع این مشکل، ورودی و Context را از منبع معتبر بخوانید و نتیجه @@TOTAL_READ را پیش از ادامه منطق با شرط صریح کنترل کنید.
خطای 3 در استفاده از @@TOTAL_READ
برای تحلیل فایل و Query باید DMVهای تخصصی استفاده شود. برای رفع این مشکل، ورودی و Context را از منبع معتبر بخوانید و نتیجه @@TOTAL_READ را پیش از ادامه منطق با شرط صریح کنترل کنید.
ملاحظات Performance برای @@TOTAL_READ
از نظر کارایی، @@TOTAL_READ زمانی کمهزینه باقی میماند که روی یک مقدار هدفمند یا مجموعه محدود اجرا شود. فراخوانی آن روی هزاران ردیف بدون Predicate اولیه میتواند CPU و زمان گزارش را افزایش دهد.
اگر گزارش به چند Property از چندین شیء نیاز دارد، استفاده Set-based از کاتالوگویو یا DMV مرتبط با disk reads معمولاً بهتر از تکرار @@TOTAL_READ برای هر سلول است.
در Jobهای دورهای، نتیجه @@TOTAL_READ را همراه Timestamp ذخیره کنید، اما Frequency نمونهبرداری را متناسب با سرعت تغییر داده انتخاب کنید. جمعآوری بیش از حد، جدول تاریخچه را بدون ارزش تحلیلی بزرگ میکند.
برای محاسبات عددی پیرامون @@TOTAL_READ، نوع داده را قبل از ضرب یا تفریق ارتقا دهید و در سناریوهای تجمعی، Restart و بازنشانی Baseline را در نظر بگیرید.
Best Practiceهای اختصاصی @@TOTAL_READ
- ورودی @@TOTAL_READ را از نام یا شناسه معتبر و دارای Schema یا Context روشن تأمین کنید.
- نتیجه NULL در @@TOTAL_READ را از مقدار صفر، false یا رشته خالی جدا نگه دارید.
- نوع خروجی @@TOTAL_READ را پیش از ذخیره یا مقایسه به نوع مقصد مناسب تبدیل کنید.
- در گزارشهای بزرگ، گزینه Set-based مرتبط با disk reads را ارزیابی کنید.
- زمان Capture، نام Database و در صورت نیاز @@SPID را کنار نتیجه @@TOTAL_READ ثبت کنید.
- مجوز مشاهده Metadata یا DMV را با حداقل سطح دسترسی لازم تنظیم کنید. در مبحث @@TOTAL_READ
- مثالهای @@TOTAL_READ را روی نسخه و Edition واقعی محیط هدف آزمایش کنید.
- برای SQL پویا، خروجی نامی @@TOTAL_READ را با QUOTENAME و پارامترسازی ایمن مصرف کنید.
تصویر سوم، تفاوت روش پرخطر و Best Practice در استفاده از @@TOTAL_READ را مقایسه میکند؛ هدف آن جلوگیری از خطاهای مربوط به این مقدار Logical Read هر Query نیست. و بهبود تصمیمگیری فنی است.
سؤالات متداول اختصاصی @@TOTAL_READ
@@TOTAL_READ دقیقاً چه مسئلهای را در SQL Server حل میکند؟
متغیر @@TOTAL_READ تعداد عملیات خواندن دیسک انجامشده توسط SQL Server را از آخرین Startup بهصورت تجمعی گزارش میکند. در عمل، با Deltaگیری دورهای میتوان شدت کلی Read I/O را پایش کرد و تغییر رفتار Workload را دید. بنابراین استفاده از @@TOTAL_READ زمانی ارزشمند است که خروجی آن در یک تصمیم فنی روشن مصرف شود، نه اینکه فقط برای نمایش عدد یا نام به کار رود.
نوع خروجی @@TOTAL_READ چیست و چگونه باید آن را مدیریت کرد؟
نوع خروجی این ابزار چنین است: integer تجمعی. بهتر است پیش از تبدیل نوع، مقایسه یا درج در جدول گزارش، حالت NULL و محدوده مقدار را صریح کنترل کنید تا رفتار @@TOTAL_READ قابل پیشبینی بماند.
آیا @@TOTAL_READ در گزارشهای سازمانی کاربرد تجاری دارد؟
بله. در سناریوهایی مانند Baseline Read و مقایسه قبل و بعد از Deployment، خروجی @@TOTAL_READ میتواند کیفیت گزارش مدیریتی را بالا ببرد. ارزش تجاری زمانی ایجاد میشود که این داده به هشدار، ظرفیتسنجی یا کاهش زمان عیبیابی متصل شود.
استفاده از @@TOTAL_READ در پروژههای بزرگ چه مزیتی دارد؟
در پروژه بزرگ، استانداردسازی نحوه استفاده از @@TOTAL_READ باعث میشود تیم توسعه، DBA و پشتیبانی یک تعریف مشترک از disk reads و physical I/O داشته باشند. این هماهنگی خطاهای تفسیر و دوبارهکاری را کاهش میدهد.
تفاوت @@TOTAL_READ با گزینه نزدیک آن چیست؟
@@TOTAL_READ شمارنده کلی Instance است؛ SET STATISTICS IO و DMVها Read را در سطح Query یا فایل نشان میدهند. انتخاب صحیح باید بر اساس حجم داده، نیاز به خروجی Set-based و سطح جزئیات گزارش انجام شود؛ یک تابع scalar همیشه جایگزین کاتالوگویو یا DMV کامل نیست.
برای طراحی اسکریپت حرفهای مبتنی بر @@TOTAL_READ چه خدماتی لازم میشود؟
در پروژههای حساس میتوان منطق @@TOTAL_READ را در قالب رویه مانیتورینگ، Dashboard، گزارش زمانبندیشده یا کنترل Deployment پیاده کرد. تحلیل نیاز، تست روی نسخه واقعی SQL Server و مستندسازی خروجی، بخشهای مهم خدمات مشاوره و انجام پروژه هستند.
رایجترین خطا هنگام کار با @@TOTAL_READ چیست؟
یکی از خطاهای مهم این است که این مقدار Logical Read هر Query نیست. همچنین نادیده گرفتن NULL یا Context اجرای Query میتواند نتیجهای ظاهراً معتبر ولی از نظر عملیاتی اشتباه تولید کند.
آیا فراخوانی زیاد @@TOTAL_READ بر Performance اثر میگذارد؟
یک فراخوانی منفرد معمولاً سبک است، اما اجرای @@TOTAL_READ روی مجموعه بسیار بزرگ یا در شرطی که برای هر ردیف محاسبه شود میتواند هزینه ایجاد کند. ابتدا ردیفها را محدود کنید و در گزارشهای وسیع، جایگزین Set-based را ارزیابی کنید.
بهترین روش استفاده از @@TOTAL_READ چیست؟
بهترین روش این است که ورودی @@TOTAL_READ اعتبارسنجی، نوع خروجی صریح، حالت NULL مدیریت و نتیجه همراه زمان و Context ثبت شود. همچنین باید مشخص باشد که خروجی برای نمایش، کنترل ایمنی یا تصمیم کارایی مصرف میشود.
@@TOTAL_READ با کدام نسخههای SQL Server سازگار است؟
متغیر سازگاری قدیمی در SQL Server است. با این حال، هنگام انتقال اسکریپت به Azure SQL یا Edition دیگر، Propertyها، مجوزهای Metadata و تفاوتهای پلتفرم را روی همان محیط آزمایش کنید.
سؤالات مصاحبه درباره @@TOTAL_READ
در مصاحبه چگونه تفاوت ورودی و خروجی @@TOTAL_READ را توضیح میدهید؟
پاسخ مناسب باید Syntax یعنی @@TOTAL_READ، نوع خروجی و شرایط NULL را توضیح دهد و یک نمونه از Baseline Read ارائه کند.
چه زمانی بهجای @@TOTAL_READ از کاتالوگویو یا DMV استفاده میکنید؟
وقتی گزارش چندین ردیف و چند Property نیاز دارد، روش Set-based معمولاً مناسبتر است؛ @@TOTAL_READ برای تبدیل یا بررسی هدفمند یک مقدار بسیار خواناست.
چگونه نتیجه نامعتبر @@TOTAL_READ را از مقدار false یا صفر جدا میکنید؟
با بررسی صریح IS NULL، اعتبارسنجی ورودی و در صورت نیاز Join با Metadata منبع، علت نتیجه را روشن میکنم. این توضیح بهطور اختصاصی به @@TOTAL_READ مربوط است.
چه نکته Performance درباره @@TOTAL_READ مهم است؟
فراخوانی را پس از محدود کردن مجموعه داده انجام میدهم و از محاسبه تکراری @@TOTAL_READ در SELECT و WHERE جلوگیری میکنم.
یک سناریوی واقعی برای @@TOTAL_READ بیان کنید.
سناریوی مناسب میتواند تحلیل Batch Job باشد؛ در آن خروجی همراه Timestamp، نام Database و شناسه نشست ثبت میشود تا قابل پیگیری باشد.
چکلیست نهایی استفاده از @@TOTAL_READ
- Syntax @@TOTAL_READ و ورودیهای آن با نسخه هدف تطبیق داده شده است.
- Context پایگاه داده یا Instance برای @@TOTAL_READ روشن است.
- مجوز لازم برای Metadata یا DMV بررسی شده است. در مبحث @@TOTAL_READ
- NULL، مقدار نامعتبر و حالت مرزی @@TOTAL_READ تست شده است.
- نمونه خروجی با نوع داده واقعی مقایسه شده است. در مبحث @@TOTAL_READ
- در Query بزرگ، هزینه فراخوانی تکراری @@TOTAL_READ اندازهگیری شده است.
- جایگزین Set-based برای گزارش انبوه ارزیابی شده است. در مبحث @@TOTAL_READ
- نتیجه نهایی همراه Timestamp و توضیح عملیاتی ثبت میشود. در مبحث @@TOTAL_READ
جمعبندی آموزش @@TOTAL_READ
@@TOTAL_READ ابزاری کوچک اما مؤثر برای با Deltaگیری دورهای میتوان شدت کلی Read I/O را پایش کرد و تغییر رفتار Workload را دید. است. استفاده حرفهای از آن به اعتبارسنجی ورودی، تفسیر نوع خروجی، کنترل NULL و انتخاب Scope مناسب وابسته است.
پس از تسلط بر @@TOTAL_READ، برای مقایسه آن با سایر ابزارهای این مجموعه به مقاله مادر توابع کمکی Performance و Metadata در SQL Server بازگردید.
خدمات برنامهنویسی و پایگاه داده
برنامهنویسی در اصفهان
قبول سفارشهای برنامهنویسی و پایگاه داده: 09131253620
انجام پروژههای برنامهنویسی، آموزش برنامهنویسی و آموزش پایگاه داده SQL Server با رویکرد حرفهای، مستند و قابل توسعه انجام میشود.
مجموعهای معتبر با سابقه فعالیت حرفهای از سال ۱۳۷۵ شمسی
از سال ۱۳۷۵ شمسی تاکنون در زمینه طراحی و اجرای پروژههای برنامهنویسی، پایگاه داده، سیستمهای تحت وب، وبسایت و راهکارهای نرمافزاری فعالیت میکنیم.
برای سفارش پروژههای برنامهنویسی و پایگاه داده، سیستمهای تحت وب، وبسایت و راهکارهای نرمافزاری جدید، با شماره تلفن همراه 09131253620 تماس حاصل فرمایید.
ایتا، واتساپ و تماس مستقیم: +989131253620
تماس با ما