MS SQL سرور کے لیے C#.NET میں LINQ سوالات کو بہتر بنانے کے کچھ پہلو

LINQ نے .NET کو ایک طاقتور نئی ڈیٹا ہیرا پھیری کی زبان کے طور پر داخل کیا ہے۔ LINQ سے SQL اس کے حصے کے طور پر آپ کو DBMS کے ساتھ کافی آسانی سے بات چیت کرنے کی اجازت دیتا ہے، مثال کے طور پر، Entity Framework۔ تاہم، اسے اکثر استعمال کرتے ہوئے، ڈویلپرز یہ دیکھنا بھول جاتے ہیں کہ آپ کے معاملے میں entity Framework، استفسار کرنے والا فراہم کنندہ کس قسم کی SQL استفسار کرے گا۔

آئیے ایک مثال کا استعمال کرتے ہوئے دو اہم نکات کو دیکھتے ہیں۔
ایسا کرنے کے لیے، ایس کیو ایل سرور میں ٹیسٹ ڈیٹا بیس بنائیں، اور درج ذیل استفسار کا استعمال کرتے ہوئے اس میں دو میزیں بنائیں:

میزیں بنانا

USE [TEST]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[Ref](
	[ID] [int] NOT NULL,
	[ID2] [int] NOT NULL,
	[Name] [nvarchar](255) NOT NULL,
	[InsertUTCDate] [datetime] NOT NULL,
 CONSTRAINT [PK_Ref] PRIMARY KEY CLUSTERED 
(
	[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[Ref] ADD  CONSTRAINT [DF_Ref_InsertUTCDate]  DEFAULT (getutcdate()) FOR [InsertUTCDate]
GO

USE [TEST]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[Customer](
	[ID] [int] NOT NULL,
	[Name] [nvarchar](255) NOT NULL,
	[Ref_ID] [int] NOT NULL,
	[InsertUTCDate] [datetime] NOT NULL,
	[Ref_ID2] [int] NOT NULL,
 CONSTRAINT [PK_Customer] PRIMARY KEY CLUSTERED 
(
	[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[Customer] ADD  CONSTRAINT [DF_Customer_Ref_ID]  DEFAULT ((0)) FOR [Ref_ID]
GO

ALTER TABLE [dbo].[Customer] ADD  CONSTRAINT [DF_Customer_InsertUTCDate]  DEFAULT (getutcdate()) FOR [InsertUTCDate]
GO

اب آئیے درج ذیل اسکرپٹ کو چلا کر ریف ٹیبل کو آباد کرتے ہیں۔

ریف ٹیبل کو بھرنا

USE [TEST]
GO

DECLARE @ind INT=1;

WHILE(@ind<1200000)
BEGIN
	INSERT INTO [dbo].[Ref]
           ([ID]
           ,[ID2]
           ,[Name])
    SELECT
           @ind
           ,@ind
           ,CAST(@ind AS NVARCHAR(255));

	SET @ind=@ind+1;
END 
GO

آئیے اسی طرح درج ذیل اسکرپٹ کا استعمال کرتے ہوئے کسٹمر ٹیبل کو بھرتے ہیں:

کسٹمر ٹیبل کو آباد کرنا

USE [TEST]
GO

DECLARE @ind INT=1;
DECLARE @ind_ref INT=1;

WHILE(@ind<=12000000)
BEGIN
	IF(@ind%3=0) SET @ind_ref=1;
	ELSE IF (@ind%5=0) SET @ind_ref=2;
	ELSE IF (@ind%7=0) SET @ind_ref=3;
	ELSE IF (@ind%11=0) SET @ind_ref=4;
	ELSE IF (@ind%13=0) SET @ind_ref=5;
	ELSE IF (@ind%17=0) SET @ind_ref=6;
	ELSE IF (@ind%19=0) SET @ind_ref=7;
	ELSE IF (@ind%23=0) SET @ind_ref=8;
	ELSE IF (@ind%29=0) SET @ind_ref=9;
	ELSE IF (@ind%31=0) SET @ind_ref=10;
	ELSE IF (@ind%37=0) SET @ind_ref=11;
	ELSE SET @ind_ref=@ind%1190000;
	
	INSERT INTO [dbo].[Customer]
	           ([ID]
	           ,[Name]
	           ,[Ref_ID]
	           ,[Ref_ID2])
	     SELECT
	           @ind,
	           CAST(@ind AS NVARCHAR(255)),
	           @ind_ref,
	           @ind_ref;


	SET @ind=@ind+1;
END
GO

اس طرح، ہمیں دو میزیں موصول ہوئیں، جن میں سے ایک میں ڈیٹا کی 1 ملین سے زیادہ قطاریں ہیں، اور دوسری میں ڈیٹا کی 10 ملین سے زیادہ قطاریں ہیں۔

اب بصری اسٹوڈیو میں آپ کو ایک ٹیسٹ ویژول C# کنسول ایپ (.NET فریم ورک) پروجیکٹ بنانے کی ضرورت ہے:

MS SQL سرور کے لیے C#.NET میں LINQ سوالات کو بہتر بنانے کے کچھ پہلو

اگلا، آپ کو ڈیٹا بیس کے ساتھ تعامل کرنے کے لیے ہستی کے فریم ورک کے لیے ایک لائبریری شامل کرنے کی ضرورت ہے۔
اسے شامل کرنے کے لیے، پروجیکٹ پر دائیں کلک کریں اور سیاق و سباق کے مینو سے NuGet پیکجز کا نظم کریں کو منتخب کریں:

MS SQL سرور کے لیے C#.NET میں LINQ سوالات کو بہتر بنانے کے کچھ پہلو

پھر، ظاہر ہونے والی NuGet پیکیج مینجمنٹ ونڈو میں، سرچ ونڈو میں لفظ "Entity Framework" درج کریں اور Entity Framework پیکیج کو منتخب کریں اور اسے انسٹال کریں:

MS SQL سرور کے لیے C#.NET میں LINQ سوالات کو بہتر بنانے کے کچھ پہلو

اگلا، App.config فائل میں، configSection عنصر کو بند کرنے کے بعد، آپ کو درج ذیل بلاک کو شامل کرنے کی ضرورت ہے:

<connectionStrings>
    <add name="DBConnection" connectionString="data source=ИМЯ_ЭКЗЕМПЛЯРА_MSSQL;Initial Catalog=TEST;Integrated Security=True;" providerName="System.Data.SqlClient" />
</connectionStrings>

کنکشن سٹرنگ میں آپ کو کنکشن سٹرنگ داخل کرنے کی ضرورت ہے۔

اب آئیے علیحدہ فائلوں میں 3 انٹرفیس بنائیں:

  1. IBaseEntityID انٹرفیس کو نافذ کرنا
    namespace TestLINQ
    {
        public interface IBaseEntityID
        {
            int ID { get; set; }
        }
    }
    

  2. IBaseEntityName انٹرفیس کا نفاذ
    namespace TestLINQ
    {
        public interface IBaseEntityName
        {
            string Name { get; set; }
        }
    }
    

  3. IBaseNameInsertUTCDate انٹرفیس کا نفاذ
    namespace TestLINQ
    {
        public interface IBaseNameInsertUTCDate
        {
            DateTime InsertUTCDate { get; set; }
        }
    }
    

اور ایک علیحدہ فائل میں ہم اپنی دو اداروں کے لیے ایک بیس کلاس BaseEntity بنائیں گے، جس میں مشترکہ فیلڈز شامل ہوں گے:

بیس کلاس BaseEntity کا نفاذ

namespace TestLINQ
{
    public class BaseEntity : IBaseEntityID, IBaseEntityName, IBaseNameInsertUTCDate
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public DateTime InsertUTCDate { get; set; }
    }
}

اگلا، ہم اپنے دو اداروں کو الگ الگ فائلوں میں بنائیں گے:

  1. ریف کلاس کا نفاذ
    using System.ComponentModel.DataAnnotations.Schema;
    
    namespace TestLINQ
    {
        [Table("Ref")]
        public class Ref : BaseEntity
        {
            public int ID2 { get; set; }
        }
    }
    

  2. کسٹمر کلاس کا نفاذ
    using System.ComponentModel.DataAnnotations.Schema;
    
    namespace TestLINQ
    {
        [Table("Customer")]
        public class Customer: BaseEntity
        {
            public int Ref_ID { get; set; }
            public int Ref_ID2 { get; set; }
        }
    }
    

اب آئیے ایک علیحدہ فائل میں UserContext سیاق و سباق بنائیں:

UserContex کلاس کا نفاذ

using System.Data.Entity;

namespace TestLINQ
{
    public class UserContext : DbContext
    {
        public UserContext()
            : base("DbConnection")
        {
            Database.SetInitializer<UserContext>(null);
        }

        public DbSet<Customer> Customer { get; set; }
        public DbSet<Ref> Ref { get; set; }
    }
}

ہمیں MS SQL سرور کے لیے EF کے ذریعے LINQ سے SQL کے ساتھ اصلاحی ٹیسٹ کرنے کے لیے ایک تیار حل موصول ہوا:

MS SQL سرور کے لیے C#.NET میں LINQ سوالات کو بہتر بنانے کے کچھ پہلو

اب Program.cs فائل میں درج ذیل کوڈ درج کریں:

Program.cs فائل

using System;
using System.Collections.Generic;
using System.Linq;

namespace TestLINQ
{
    class Program
    {
        static void Main(string[] args)
        {
            using (UserContext db = new UserContext())
            {
                var dblog = new List<string>();
                db.Database.Log = dblog.Add;

                var query = from e1 in db.Customer
                            from e2 in db.Ref
                            where (e1.Ref_ID == e2.ID)
                                 && (e1.Ref_ID2 == e2.ID2)
                            select new { Data1 = e1.Name, Data2 = e2.Name };

                var result = query.Take(1000).ToList();

                Console.WriteLine(dblog[1]);

                Console.ReadKey();
            }
        }
    }
}

اگلا، آئیے اپنا پروجیکٹ شروع کرتے ہیں۔

کام کے اختتام پر، مندرجہ ذیل کنسول پر دکھایا جائے گا:

ایس کیو ایل استفسار

SELECT TOP (1000) 
    [Extent1].[Ref_ID] AS [Ref_ID], 
    [Extent1].[Name] AS [Name], 
    [Extent2].[Name] AS [Name1]
    FROM  [dbo].[Customer] AS [Extent1]
    INNER JOIN [dbo].[Ref] AS [Extent2] ON ([Extent1].[Ref_ID] = [Extent2].[ID]) AND ([Extent1].[Ref_ID2] = [Extent2].[ID2])

یعنی، عام طور پر، LINQ استفسار نے MS SQL Server DBMS کے لیے ایک SQL استفسار بہت اچھی طرح سے تیار کیا۔

اب LINQ استفسار میں AND کی حالت کو OR میں تبدیل کریں:

LINQ استفسار

var query = from e1 in db.Customer
                            from e2 in db.Ref
                            where (e1.Ref_ID == e2.ID)
                                || (e1.Ref_ID2 == e2.ID2)
                            select new { Data1 = e1.Name, Data2 = e2.Name };

اور آئیے اپنی ایپلیکیشن دوبارہ شروع کریں۔

کمانڈ پر عمل درآمد کا وقت 30 سیکنڈ سے زیادہ ہونے کی وجہ سے ایگزیکیوشن خرابی کے ساتھ کریش ہو جائے گا:

MS SQL سرور کے لیے C#.NET میں LINQ سوالات کو بہتر بنانے کے کچھ پہلو

اگر آپ اس استفسار کو دیکھیں جو LINQ کے ذریعہ تیار کی گئی تھی:

MS SQL سرور کے لیے C#.NET میں LINQ سوالات کو بہتر بنانے کے کچھ پہلو
، پھر آپ اس بات کو یقینی بنا سکتے ہیں کہ انتخاب دو سیٹوں (ٹیبلز) کے کارٹیشین مصنوع کے ذریعے ہوتا ہے:

ایس کیو ایل استفسار

SELECT TOP (1000) 
    [Extent1].[Ref_ID] AS [Ref_ID], 
    [Extent1].[Name] AS [Name], 
    [Extent2].[Name] AS [Name1]
    FROM  [dbo].[Customer] AS [Extent1]
    CROSS JOIN [dbo].[Ref] AS [Extent2]
    WHERE [Extent1].[Ref_ID] = [Extent2].[ID] OR [Extent1].[Ref_ID2] = [Extent2].[ID2]

آئیے LINQ استفسار کو اس طرح دوبارہ لکھتے ہیں:

آپٹمائزڈ LINQ استفسار

var query = (from e1 in db.Customer
                   join e2 in db.Ref
                   on e1.Ref_ID equals e2.ID
                   select new { Data1 = e1.Name, Data2 = e2.Name }).Union(
                        from e1 in db.Customer
                        join e2 in db.Ref
                        on e1.Ref_ID2 equals e2.ID2
                        select new { Data1 = e1.Name, Data2 = e2.Name });

پھر ہمیں درج ذیل SQL استفسار ملتا ہے۔

SQL استفسار

SELECT 
    [Limit1].[C1] AS [C1], 
    [Limit1].[C2] AS [C2], 
    [Limit1].[C3] AS [C3]
    FROM ( SELECT DISTINCT TOP (1000) 
        [UnionAll1].[C1] AS [C1], 
        [UnionAll1].[Name] AS [C2], 
        [UnionAll1].[Name1] AS [C3]
        FROM  (SELECT 
            1 AS [C1], 
            [Extent1].[Name] AS [Name], 
            [Extent2].[Name] AS [Name1]
            FROM  [dbo].[Customer] AS [Extent1]
            INNER JOIN [dbo].[Ref] AS [Extent2] ON [Extent1].[Ref_ID] = [Extent2].[ID]
        UNION ALL
            SELECT 
            1 AS [C1], 
            [Extent3].[Name] AS [Name], 
            [Extent4].[Name] AS [Name1]
            FROM  [dbo].[Customer] AS [Extent3]
            INNER JOIN [dbo].[Ref] AS [Extent4] ON [Extent3].[Ref_ID2] = [Extent4].[ID2]) AS [UnionAll1]
    )  AS [Limit1]

افسوس، LINQ سوالات میں صرف ایک جوائن کنڈیشن ہو سکتی ہے، لہذا یہاں یہ ممکن ہے کہ ہر کنڈیشن کے لیے دو استفسارات کا استعمال کرتے ہوئے مساوی استفسار کیا جائے اور پھر ان کو یونین کے ذریعے ملا کر قطاروں میں سے ڈپلیکیٹس کو ہٹا دیا جائے۔
ہاں، سوالات عام طور پر غیر مساوی ہوں گے، اس بات کو مدنظر رکھتے ہوئے کہ مکمل ڈپلیکیٹ قطاریں واپس کی جا سکتی ہیں۔ تاہم، حقیقی زندگی میں، مکمل ڈپلیکیٹ لائنوں کی ضرورت نہیں ہے اور لوگ ان سے چھٹکارا حاصل کرنے کی کوشش کرتے ہیں.

اب آئیے ان دو سوالات کے نفاذ کے منصوبوں کا موازنہ کریں:

  1. CROSS JOIN کے لیے عمل درآمد کا اوسط وقت 195 سیکنڈ ہے:
    MS SQL سرور کے لیے C#.NET میں LINQ سوالات کو بہتر بنانے کے کچھ پہلو
  2. INNER JOIN-UNION کے لیے عمل درآمد کا اوسط وقت 24 سیکنڈ سے کم ہے:
    MS SQL سرور کے لیے C#.NET میں LINQ سوالات کو بہتر بنانے کے کچھ پہلو

جیسا کہ آپ نتائج سے دیکھ سکتے ہیں، لاکھوں ریکارڈ کے ساتھ دو جدولوں کے لیے، آپٹمائزڈ LINQ استفسار غیر اصلاح شدہ سے کئی گنا تیز ہے۔

شرائط میں AND کے ساتھ اختیار کے لیے، فارم کا ایک LINQ استفسار:

LINQ استفسار

var query = from e1 in db.Customer
                            from e2 in db.Ref
                            where (e1.Ref_ID == e2.ID)
                                 && (e1.Ref_ID2 == e2.ID2)
                            select new { Data1 = e1.Name, Data2 = e2.Name };

درست SQL استفسار تقریباً ہمیشہ ہی تیار کیا جائے گا، جو اوسطاً 1 سیکنڈ میں چلے گا:

MS SQL سرور کے لیے C#.NET میں LINQ سوالات کو بہتر بنانے کے کچھ پہلو
نیز LINQ سے آبجیکٹ کی ہیرا پھیری کے لیے سوال کی بجائے جیسے:

LINQ استفسار (پہلا آپشن)

var query = from e1 in seq1
                            from e2 in seq2
                            where (e1.Key1==e2.Key1)
                               && (e1.Key2==e2.Key2)
                            select new { Data1 = e1.Data, Data2 = e2.Data };

آپ ایک استفسار استعمال کرسکتے ہیں جیسے:

LINQ استفسار (پہلا آپشن)

var query = from e1 in seq1
                            join e2 in seq2
                            on new { e1.Key1, e1.Key2 } equals new { e2.Key1, e2.Key2 }
                            select new { Data1 = e1.Data, Data2 = e2.Data };

جہاں:

دو صفوں کی وضاحت کرنا

Para[] seq1 = new[] { new Para { Key1 = 1, Key2 = 2, Data = "777" }, new Para { Key1 = 2, Key2 = 3, Data = "888" }, new Para { Key1 = 3, Key2 = 4, Data = "999" } };
Para[] seq2 = new[] { new Para { Key1 = 1, Key2 = 2, Data = "777" }, new Para { Key1 = 2, Key2 = 3, Data = "888" }, new Para { Key1 = 3, Key2 = 5, Data = "999" } };

، اور پیرا کی قسم کی وضاحت اس طرح کی گئی ہے:

پیرا ٹائپ ڈیفینیشن

class Para
{
        public int Key1, Key2;
        public string Data;
}

اس طرح، ہم نے MS SQL سرور کے لیے LINQ سوالات کو بہتر بنانے میں کچھ پہلوؤں کا جائزہ لیا۔

بدقسمتی سے، یہاں تک کہ تجربہ کار اور سرکردہ .NET ڈویلپرز بھول جاتے ہیں کہ انہیں یہ سمجھنے کی ضرورت ہے کہ وہ جو ہدایات استعمال کرتے ہیں وہ پردے کے پیچھے کیا کرتے ہیں۔ بصورت دیگر، وہ کنفیگریٹر بن جاتے ہیں اور سافٹ ویئر سلوشن کو اسکیل کرتے وقت اور بیرونی ماحولیاتی حالات میں معمولی تبدیلیوں کے ساتھ مستقبل میں ٹائم بم لگا سکتے ہیں۔

ایک مختصر جائزہ بھی لیا گیا۔ یہاں.

ٹیسٹ کے ذرائع - خود پروجیکٹ، TEST ڈیٹا بیس میں ٹیبلز کی تخلیق کے ساتھ ساتھ ان ٹیبلز کو ڈیٹا سے بھرنا بھی واقع ہے۔ یہاں.
اس کے علاوہ اس ذخیرہ میں، پلانز فولڈر میں، OR شرائط کے ساتھ استفسارات کو انجام دینے کے منصوبے ہیں۔

ماخذ: www.habr.com

نیا تبصرہ شامل کریں