پېژندنه
В د اصلاح کولو ځینې میتودونه په پام کې نیول شوي د LINQ پوښتنې.
دلته موږ د کوډ اصلاح کولو پورې اړوند ځینې نورې لارې هم وړاندې کوو د LINQ پوښتنې.
دا معلومه ده چې لینک(Language-Integrated Query) د معلوماتو سرچینې د پوښتنې لپاره یوه ساده او اسانه ژبه ده.
А لینک SQL ته په DBMS کې معلوماتو ته د لاسرسي لپاره ټیکنالوژي ده. دا د ډیټا سره د کار کولو لپاره یو پیاوړی وسیله ده، چیرې چې پوښتنې د اعلاناتي ژبې له لارې رامینځته کیږي، چې بیا به یې بدل شي. د SQL پوښتنې پلیټ فارم او د اجرا کولو لپاره ډیټابیس سرور ته لیږل شوی. زموږ په قضیه کې، د DBMS لخوا موږ معنی لرو د MS SQL پالنګر.
په هرصورت، د LINQ پوښتنې په غوره لیکل شویو کې نه بدلیږي د SQL پوښتنې، کوم چې تجربه لرونکي DBA کولی شي د اصلاح کولو ټولو باریکیو سره ولیکي د SQL پوښتنې:
- غوره اړیکې (کول) او پایلې فلټر کول (کله چې)
- د اړیکو او ګروپ شرایطو په کارولو کې ډیری لنډیزونه
- د شرایطو په بدلولو کې ډیری توپیرونه IN په شتون لريи نه په, <> آن شتون لري
- د لنډمهاله جدولونو، CTE، جدول متغیرونو له لارې د پایلو منځمهاله زیرمه کول
- د جملې کارول (اختیار) د لارښوونو او میز اشارو سره سره (...)
- د انتخابونو پرمهال د بې ځایه معلوماتو لوستلو څخه د خلاصون لپاره د یوې وسیلې په توګه د شاخص شوي لیدونو کارول
د پایلې اصلي فعالیت خنډونه د SQL پوښتنې کله چې تالیف کول د LINQ پوښتنې دي:
- په یوه غوښتنه کې د ټول ډیټا انتخاب میکانیزم یوځای کول
- د کوډ د ورته بلاکونو نقل کول، کوم چې په نهایت کې د ډیری غیر ضروري معلوماتو لوستلو لامل کیږي
- د څو برخو شرایطو ګروپونه (منطقي "او" او "یا") - او и OR، د پیچلو شرایطو سره یوځای کول د دې حقیقت لامل کیږي چې اصلاح کونکی ، د اړینو ساحو لپاره مناسب غیر کلستر شوي شاخصونه لري ، په نهایت کې د کلستر شوي شاخص پروړاندې سکین کول پیل کوي (د انډیکس سکین) د شرایطو ګروپونو له مخې
- د فرعي پوښتنو ژور ځړول تحلیل کول خورا ستونزمن کوي د SQL بیانونه او د پراختیا کونکو لخوا د پوښتنې پلان تحلیل او DBA
د اصلاح کولو طریقې
اوس راځئ چې مستقیم د اصلاح کولو میتودونو ته لاړ شو.
1) اضافي لیست کول
دا غوره ده چې د اصلي انتخاب په میزونو کې فلټرونه په پام کې ونیسئ، ځکه چې ډیری وختونه ټوله پوښتنه د یو یا دوه اصلي میزونو (د غوښتنلیکونو-خلکو-عملیات) په شاوخوا کې جوړه شوې وي او د شرایطو معیاري سیټ سره (IsClosed، Canceled، Enabled، Status). دا مهمه ده چې د پیژندل شوي نمونو لپاره مناسب شاخصونه جوړ کړئ.
دا حل معنی لري کله چې د دې ساحو غوره کول د پام وړ پوښتنې ته راستانه شوي سیټ محدودوي.
د مثال په توګه، موږ 500000 غوښتنلیکونه لرو. په هرصورت، یوازې 2000 فعال غوښتنلیکونه شتون لري. بیا په سمه توګه ټاکل شوی شاخص به موږ له دې څخه وژغوري د انډیکس سکین په لوی میز کې او تاسو ته به اجازه درکړي په چټکۍ سره د غیر کلستر شوي شاخص له لارې ډاټا غوره کړئ.
همدارنګه، د شاخصونو نشتوالی د پوښتنو پلانونو پارس کولو یا د سیسټم لید احصایې راټولولو لپاره د اشارو له لارې پیژندل کیدی شي د MS SQL پالنګر:
د لید ټول معلومات د ځایی شاخصونو استثنا سره د ورک شوي شاخصونو په اړه معلومات لري.
په هرصورت، شاخصونه او کیشینګ اکثرا د ناسم لیکلو پایلو سره د مبارزې میتودونه دي د LINQ پوښتنې и د SQL پوښتنې.
لکه څنګه چې د ژوند سخت تمرین ښیي، دا د سوداګرۍ لپاره ډیری وختونه مهم دي چې د ټاکلو وختونو لخوا د سوداګرۍ ځانګړتیاوې پلي کړي. او له همدې امله، درنې غوښتنې اکثرا د کیچ کولو سره پس منظر ته لیږدول کیږي.
دا یو څه توجیه کیږي، ځکه چې کاروونکي تل وروستي معلوماتو ته اړتیا نلري او د کاروونکي انٹرفیس د منلو وړ کچه شتون لري.
دا طریقه د سوداګرۍ اړتیاوو حل کولو ته اجازه ورکوي، مګر په نهایت کې د معلوماتو سیسټم فعالیت په ساده ډول د ستونزو حل کولو ځنډولو سره کموي.
دا هم د یادولو وړ ده چې د وړاندیزونو اضافه کولو لپاره د اړین شاخصونو لټون کولو په جریان کې MS SQL اصلاح کول ممکن غلط وي، په شمول د لاندې شرایطو لاندې:
- که چیرې دمخه د ورته ساحو سره شاخصونه شتون ولري
- که چیرې په جدول کې ساحې د شاخص کولو محدودیتونو له امله شاخص نشي (په ډیر تفصیل سره تشریح شوي) ).
2) د صفاتو یوځای کول په یوه نوي صفت کې
ځینې وختونه د یو میز څخه ځینې ساحې، چې د شرایطو د یوې ډلې لپاره د اساس په توګه کار کوي، د یوې نوې ساحې په معرفي کولو سره بدلیدلی شي.
دا په ځانګړې توګه د حالت ساحو لپاره ریښتیا ده، کوم چې معمولا په ډول کې بټ یا بشپړ وي.
بېلګه:
تړل شوی = 0 او منسوخ شوی = 0 او فعال شوی = 0 لخوا ځای په ځای شوی حالت = 1.
دا هغه ځای دی چې د بشپړ حالت حالت ځانګړتیا معرفي کیږي ترڅو ډاډ ترلاسه کړي چې دا حالتونه په جدول کې آباد شوي. بیا، دا نوې ځانګړتیا په نښه شوې ده.
دا د فعالیت ستونزې بنسټیز حل دی، ځکه چې موږ د غیر ضروري محاسبې پرته ډاټا ته لاسرسی لرو.
3) د لید مادي کول
له بده مرغه په د LINQ پوښتنې لنډمهاله میزونه، CTEs، او د جدول متغیرونه په مستقیم ډول نشي کارول کیدی.
په هرصورت، د دې قضیې لپاره د ښه کولو لپاره بله لاره شتون لري - د لید لید.
د شرایطو ګروپ (د پورته مثال څخه) تړل شوی = 0 او منسوخ شوی = 0 او فعال شوی = 0 (یا د نورو ورته شرایطو یوه مجموعه) یو ښه انتخاب دی چې دوی په یوه شاخص شوي لید کې وکاروئ ، د لوی سیټ څخه د ډیټا کوچنۍ ټوټې کیچ کول.
مګر یو شمیر محدودیتونه شتون لري کله چې یو نظر عملي کوي:
- د فرعي پوښتنو، بندونو کارول شتون لري باید په کارولو سره بدل شي کول
- تاسو جملې نشي کارولی یونین, یونین ټول, استثمار, د
- تاسو نشئ کولی د جدول اشارې او بندونه وکاروئ اختیار
- د سایکل سره د کار کولو امکان نشته
- د مختلفو جدولونو څخه په یوه لید کې د معلوماتو ښودل ناممکن دي
دا مهمه ده چې په یاد ولرئ چې د شاخص شوي لید کارولو اصلي ګټه یوازې د واقعیا د شاخص کولو سره ترلاسه کیدی شي.
مګر کله چې لید ته زنګ ووهئ، دا شاخصونه نشي کارول کیدی، او په ښکاره توګه د کارولو لپاره، تاسو باید مشخص کړئ سره (NOEXPAND).
له هغه راهیسې د LINQ پوښتنې د میز اشارې تعریف کول ناممکن دي، نو تاسو باید یو بل نمایش جوړ کړئ - د لاندې بڼې "ریپر":
CREATE VIEW ИМЯ_представления AS SELECT * FROM MAT_VIEW WITH (NOEXPAND);
4) د میز د کارونو کارول
ډیری وختونه په کې د LINQ پوښتنې د فرعي پوښتنو یا بلاکونو لوی بلاکونه د پیچلي جوړښت سره د لیدونو په کارولو سره د خورا پیچلي او فرعي غوره اجرا کولو جوړښت سره وروستۍ پوښتنه رامینځته کوي.
د جدول د دندو د کارولو کلیدي ګټې د LINQ پوښتنې:
- وړتیا، لکه څنګه چې د نظرونو په قضیه کې، د یو څیز په توګه کارول او مشخص شوي، مګر تاسو کولی شئ د ان پټ پیرامیټونو سیټ تیر کړئ:
له فنکشن څخه (@param1, @param2 ...)
د پایلې په توګه، د انعطاف وړ ډاټا نمونې ترلاسه کیدی شي - د جدول فنکشن کارولو په حالت کې، هیڅ داسې قوي محدودیتونه شتون نلري لکه څنګه چې پورته بیان شوي د شاخص شوي نظرونو په صورت کې:
- جدول اشاره:
له لارې د لینک تاسو نشئ کولی مشخص کړئ چې کوم شاخصونه باید وکارول شي او د پوښتنې کولو پرمهال د ډیټا جلا کولو کچه مشخص کړئ.
مګر فعالیت دا وړتیاوې لري.
د فنکشن سره ، تاسو کولی شئ د کافي دوامداره اجرا کولو پوښتنې پلان ترلاسه کړئ ، چیرې چې د شاخصونو او ډیټا جلا کولو کچې سره د کار کولو قواعد تعریف شوي - د فنکشن کارول اجازه ورکوي چې د شاخص شوي لیدونو په پرتله ترلاسه کړي:
- د پیچلي معلوماتو نمونې کولو منطق (حتی د لوپونو کارول)
- د ډیری مختلف میزونو څخه ډاټا ترلاسه کول
- د استعمال یونین и شتون لري
- جدول اشاره:
- وړاندیز اختیار ډیر ګټور کله چې موږ د همغږۍ کنټرول چمتو کولو ته اړتیا لرو اختیار(MAXDOP N)د پوښتنو د اجرا کولو پلان ترتیب. د مثال په ډول:
- تاسو کولی شئ د پوښتنې پلان جبري بیا جوړونه مشخص کړئ اختیار (بیا جوړ کړئ)
- تاسو کولی شئ مشخص کړئ چې ایا د پوښتنې پلان مجبور کړئ چې په پوښتنه کې مشخص شوي د یوځای کیدو امر وکاروئ اختیار (د زور امر)
په اړه نور جزئیات اختیار بیان شوی .
- د خورا تنګ او خورا اړین ډیټا سلائس کارول:
په کیچونو کې د لوی ډیټا سیټونو ذخیره کولو ته اړتیا نشته (لکه څنګه چې د شاخص شوي لیدونو قضیه ده) ، له کوم ځای څخه تاسو لاهم اړتیا لرئ ډیټا د پیرامیټر لخوا فلټر کړئ.
د مثال په توګه، یو جدول شتون لري چې فلټر کله چې درې ساحې کارول کیږي (a,b,c).په دودیز ډول، ټولې غوښتنې یو ثابت حالت لري a = 0 او b = 0.
په هرصورت، د ساحې غوښتنه c ډیر متغیر.
اجازه راکړئ چې حالت a = 0 او b = 0 دا واقعیا له موږ سره مرسته کوي چې د اړتیا وړ پایلې سیټ په زرګونو ریکارډونو ته محدود کړو ، مګر حالت с انتخاب سل ریکارډونو ته محدودوي.
دلته د میز فعالیت ممکن غوره انتخاب وي.
همچنان ، د جدول فعالیت د اجرا کولو وخت کې ډیر وړاندوینه او ثابت دی.
مثالونه
راځئ چې د مثال په توګه د پوښتنو ډیټابیس کارولو مثال پلي کولو ته وګورو.
یوه غوښتنه ده غوره کول، کوم چې ډیری جدولونه سره یوځای کوي او یو لید کاروي (عملي پوښتنې) ، په کوم کې چې تړاو د بریښنالیک له لارې چک کیږي (له لارې شتون لري) تر "عملي پوښتنو" ته:
غوښتنه نمبر 1
(@p__linq__0 nvarchar(4000))SELECT
1 AS [C1],
[Extent1].[Id] AS [Id],
[Join2].[Object_Id] AS [Object_Id],
[Join2].[ObjectType_Id] AS [ObjectType_Id],
[Join2].[Name] AS [Name],
[Join2].[ExternalId] AS [ExternalId]
FROM [dbo].[Questions] AS [Extent1]
INNER JOIN (SELECT [Extent2].[Object_Id] AS [Object_Id],
[Extent2].[Question_Id] AS [Question_Id], [Extent3].[ExternalId] AS [ExternalId],
[Extent3].[ObjectType_Id] AS [ObjectType_Id], [Extent4].[Name] AS [Name]
FROM [dbo].[ObjectQuestions] AS [Extent2]
INNER JOIN [dbo].[Objects] AS [Extent3] ON [Extent2].[Object_Id] = [Extent3].[Id]
LEFT OUTER JOIN [dbo].[ObjectTypes] AS [Extent4]
ON [Extent3].[ObjectType_Id] = [Extent4].[Id] ) AS [Join2]
ON [Extent1].[Id] = [Join2].[Question_Id]
WHERE ([Extent1].[AnswerId] IS NULL) AND (0 = [Extent1].[Exp]) AND ( EXISTS (SELECT
1 AS [C1]
FROM [dbo].[OperativeQuestions] AS [Extent5]
WHERE (([Extent5].[Email] = @p__linq__0) OR (([Extent5].[Email] IS NULL)
AND (@p__linq__0 IS NULL))) AND ([Extent5].[Id] = [Extent1].[Id])
));
لید یو ډیر پیچلی جوړښت لري: دا فرعي پوښتنې لري او ترتیب کول کاروي DISTINCT، کوم چې په عموم کې د منابعو له پلوه کافي عملیات دی.
د عملیاتي پوښتنو څخه یوه نمونه شاوخوا لس زره ریکارډونه دي.
د دې پوښتنې سره اصلي ستونزه دا ده چې د بهرنۍ پوښتنې څخه د ریکارډونو لپاره، داخلي فرعي پوښتنې په [OperativeQuestions] لید کې اجرا کیږي، کوم چې باید د [Email] = @p__linq__0 لپاره موږ ته اجازه راکړو چې د محصول انتخاب محدود کړو (له لارې شتون لريتر سلګونو ریکارډونو پورې.
او داسې ښکاري چې فرعي پوښتنې باید یو ځل د [Email] = @p__linq__0 له لارې ریکارډونه محاسبه کړي، او بیا دا څو سوه ریکارډونه باید د پوښتنو سره د ID لخوا وصل شي، او پوښتنه به چټکه وي.
په حقیقت کې، د ټولو جدولونو یو ترتیبي اړیکه شتون لري: د عملیاتي پوښتنو څخه د ID سره د ID پوښتنو لیکونو چک کول، او د بریښنالیک له لارې فلټر کول.
په حقیقت کې، غوښتنه د ټولو لسګونو زرو عملیاتي پوښتنو ریکارډونو سره کار کوي، مګر یوازې د ګټو ډاټا ته د بریښنالیک له لارې اړتیا ده.
عملیاتي پوښتنې متن وګورئ:
غوښتنه نمبر 2
CREATE VIEW [dbo].[OperativeQuestions]
AS
SELECT DISTINCT Q.Id, USR.email AS Email
FROM [dbo].Questions AS Q INNER JOIN
[dbo].ProcessUserAccesses AS BPU ON BPU.ProcessId = CQ.Process_Id
OUTER APPLY
(SELECT 1 AS HasNoObjects
WHERE NOT EXISTS
(SELECT 1
FROM [dbo].ObjectUserAccesses AS BOU
WHERE BOU.ProcessUserAccessId = BPU.[Id] AND BOU.[To] IS NULL)
) AS BO INNER JOIN
[dbo].Users AS USR ON USR.Id = BPU.UserId
WHERE CQ.[Exp] = 0 AND CQ.AnswerId IS NULL AND BPU.[To] IS NULL
AND (BO.HasNoObjects = 1 OR
EXISTS (SELECT 1
FROM [dbo].ObjectUserAccesses AS BOU INNER JOIN
[dbo].ObjectQuestions AS QBO
ON QBO.[Object_Id] =BOU.ObjectId
WHERE BOU.ProcessUserAccessId = BPU.Id
AND BOU.[To] IS NULL AND QBO.Question_Id = CQ.Id));
په DbContext کې د لومړني لید نقشه کول (EF کور 2)
public class QuestionsDbContext : DbContext
{
//...
public DbQuery<OperativeQuestion> OperativeQuestions { get; set; }
//...
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Query<OperativeQuestion>().ToView("OperativeQuestions");
}
}
د LINQ لومړنۍ پوښتنه
var businessObjectsData = await context
.OperativeQuestions
.Where(x => x.Email == Email)
.Include(x => x.Question)
.Select(x => x.Question)
.SelectMany(x => x.ObjectQuestions,
(x, bo) => new
{
Id = x.Id,
ObjectId = bo.Object.Id,
ObjectTypeId = bo.Object.ObjectType.Id,
ObjectTypeName = bo.Object.ObjectType.Name,
ObjectExternalId = bo.Object.ExternalId
})
.ToListAsync();
په دې ځانګړې قضیه کې، موږ د دې ستونزې حل په پام کې نیسو پرته له زیربنایي بدلونونو، پرته له دې چې د چمتو شوي پایلو ("فعال پوښتنو") سره جلا جدول معرفي کړو، کوم چې د معلوماتو سره ډکولو او تازه ساتلو لپاره میکانیزم ته اړتیا لري. .
که څه هم دا یو ښه حل دی، د دې ستونزې د ښه کولو لپاره بله لاره شتون لري.
اصلي هدف د عملیاتي پوښتنو لید څخه د [بریښنالیک] = @p__linq__0 لخوا د ننوتلو زیرمه کول دي.
ډیټابیس ته د جدول فنکشن [dbo] [OperativeQuestionsUserMail] معرفي کړئ.
د ان پټ پیرامیټر په توګه د بریښنالیک لیږلو سره، موږ د ارزښتونو جدول بیرته ترلاسه کوو:
غوښتنه نمبر 3
CREATE FUNCTION [dbo].[OperativeQuestionsUserMail]
(
@Email nvarchar(4000)
)
RETURNS
@tbl TABLE
(
[Id] uniqueidentifier,
[Email] nvarchar(4000)
)
AS
BEGIN
INSERT INTO @tbl ([Id], [Email])
SELECT Id, @Email
FROM [OperativeQuestions] AS [x] WHERE [x].[Email] = @Email;
RETURN;
END
دا د مخکې ټاکل شوي ډاټا جوړښت سره د ارزښتونو جدول راګرځوي.
د دې لپاره چې د عملیاتي پوښتنو یوزر میل ته د پوښتنو لپاره غوره وي او د پوښتنو غوره پلانونه ولري، یو سخت جوړښت ته اړتیا ده، او نه د راستنیدو جدول د بیرته راستنیدو په توګه...
په دې حالت کې، اړین پوښتنه 1 په 4 پوښتنې بدله شوې:
غوښتنه نمبر 4
(@p__linq__0 nvarchar(4000))SELECT
1 AS [C1],
[Extent1].[Id] AS [Id],
[Join2].[Object_Id] AS [Object_Id],
[Join2].[ObjectType_Id] AS [ObjectType_Id],
[Join2].[Name] AS [Name],
[Join2].[ExternalId] AS [ExternalId]
FROM (
SELECT Id, Email FROM [dbo].[OperativeQuestionsUserMail] (@p__linq__0)
) AS [Extent0]
INNER JOIN [dbo].[Questions] AS [Extent1] ON([Extent0].Id=[Extent1].Id)
INNER JOIN (SELECT [Extent2].[Object_Id] AS [Object_Id], [Extent2].[Question_Id] AS [Question_Id], [Extent3].[ExternalId] AS [ExternalId], [Extent3].[ObjectType_Id] AS [ObjectType_Id], [Extent4].[Name] AS [Name]
FROM [dbo].[ObjectQuestions] AS [Extent2]
INNER JOIN [dbo].[Objects] AS [Extent3] ON [Extent2].[Object_Id] = [Extent3].[Id]
LEFT OUTER JOIN [dbo].[ObjectTypes] AS [Extent4]
ON [Extent3].[ObjectType_Id] = [Extent4].[Id] ) AS [Join2]
ON [Extent1].[Id] = [Join2].[Question_Id]
WHERE ([Extent1].[AnswerId] IS NULL) AND (0 = [Extent1].[Exp]);
په DbContext (EF Core 2) کې د لیدونو نقشه کول او دندې
public class QuestionsDbContext : DbContext
{
//...
public DbQuery<OperativeQuestion> OperativeQuestions { get; set; }
//...
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Query<OperativeQuestion>().ToView("OperativeQuestions");
}
}
public static class FromSqlQueries
{
public static IQueryable<OperativeQuestion> GetByUserEmail(this DbQuery<OperativeQuestion> source, string Email)
=> source.FromSql($"SELECT Id, Email FROM [dbo].[OperativeQuestionsUserMail] ({Email})");
}
د LINQ وروستۍ پوښتنه
var businessObjectsData = await context
.OperativeQuestions
.GetByUserEmail(Email)
.Include(x => x.Question)
.Select(x => x.Question)
.SelectMany(x => x.ObjectQuestions,
(x, bo) => new
{
Id = x.Id,
ObjectId = bo.Object.Id,
ObjectTypeId = bo.Object.ObjectType.Id,
ObjectTypeName = bo.Object.ObjectType.Name,
ObjectExternalId = bo.Object.ExternalId
})
.ToListAsync();
د اجرا کولو وخت ترتیب له 200-800 ms څخه 2-20 ms ته راټیټ شوی، او داسې نور، د بیلګې په توګه لسګونه ځله ګړندی.
که موږ دا په اوسط ډول واخلو ، نو د 350 ms پرځای موږ 8 ms ترلاسه کړل.
د ښکاره ګټو څخه موږ هم ترلاسه کوو:
- د لوستلو بار کې عمومي کمښت ،
- د بندیدو احتمال کې د پام وړ کمښت
- د منلو وړ ارزښتونو ته د اوسط بلاک کولو وخت کمول
پایلې
د ډیټابیس کالونو اصلاح کول او ښه تنظیم کول MS SQL له لارې د لینک یوه ستونزه ده چې حل کیدی شي.
په دې کار کې توجه او تداوم خورا مهم دي.
د پروسې په پیل کې:
- دا اړینه ده چې هغه ډیټا چیک کړئ چې ورسره غوښتنه کار کوي (ارزښتونه ، د ټاکل شوي ډیټا ډولونه)
- د دې ارقامو مناسب شاخص ترسره کړئ
- د جدولونو تر مینځ د یوځای کیدو شرایط چیک کړئ
د اصلاح کولو راتلونکی تکرار څرګندوي:
- د غوښتنې اساس او د اصلي غوښتنې فلټر تعریفوي
- د ورته پوښتنو بلاکونو تکرار او د شرایطو تقاطع تحلیل
- د SSMS یا نورو GUI لپاره SQL سرور خپل ځان اصلاح کوي د SQL پوښتنه (د منځګړیتوب ډیټا ذخیره تخصیص کول، د دې ذخیرې په کارولو سره د پایلې پوښتنې رامینځته کول (شاید ډیری وي))
- په وروستي مرحله کې، نتیجه د اساس په توګه اخیستل د SQL پوښتنه، جوړښت بیا رغول کیږي د LINQ پوښتنه
پایله د LINQ پوښتنه باید په جوړښت کې د پیژندل شوي مطلوب سره ورته وي د SQL پوښتنه له 3 نقطې څخه.
اعترافونه
د همکارانو څخه ډیره مننه и له شرکت څخه قلعه د دې موادو په چمتو کولو کې د مرستې لپاره.
سرچینه: www.habr.com
