د MS SQL سرور لپاره په C#.NET کې د LINQ پوښتنو د اصلاح کولو ځینې اړخونه

LINQ .NET د یوې پیاوړې نوې ډیټا مینځلو ژبې په توګه داخل شو. د یوې برخې په توګه SQL ته LINQ تاسو ته اجازه درکوي چې د DBMS په کارولو سره په اسانۍ سره اړیکه ونیسئ، د بیلګې په توګه، د ادارې چوکاټ. په هرصورت، ډیری وختونه د دې کارولو سره، پراختیا کونکي هیروي چې وګوري چې کوم ډول SQL پوښتنې د پوښتنې وړ چمتو کونکي، ستاسو په قضیه کې د ادارې چوکاټ به تولید کړي.

راځئ چې د مثال په کارولو سره دوه اصلي ټکي وګورو.
د دې کولو لپاره، په 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 بسته مدیریت کړکۍ کې چې څرګندیږي ، د لټون کړکۍ کې د "ادارې چوکاټ" کلمه دننه کړئ او د وجود چوکاټ کڅوړه غوره کړئ او نصب یې کړئ:

د MS SQL سرور لپاره په C#.NET کې د LINQ پوښتنو د اصلاح کولو ځینې اړخونه

بیا ، د App.config فایل کې ، د تشکیل برخې عنصر بندولو وروسته ، تاسو اړتیا لرئ لاندې بلاک اضافه کړئ:

<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 پلي کول

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

بیا، موږ به خپل دوه ادارې په جلا فایلونو کې جوړ کړو:

  1. د Ref ټولګي پلي کول
    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();
            }
        }
    }
}

بیا، راځئ چې زموږ پروژه پیل کړو.

د کار په پای کې، لاندې به په کنسول کې ښکاره شي:

د SQL پوښتنې پیدا شوې

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 سرور DBMS ته د SQL پوښتنه په ښه توګه رامینځته کړې.

اوس راځئ چې د لینک پوښتنې کې د 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 پوښتنو د اصلاح کولو ځینې اړخونه
، بیا تاسو کولی شئ ډاډ ترلاسه کړئ چې انتخاب د دوه سیټونو (میزونو) د کارټیسین محصول له لارې پیښیږي:

د SQL پوښتنې پیدا شوې

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. د داخلي یو ځای کیدو لپاره د اوسط اجرا کولو وخت له 24 ثانیو څخه کم دی:
    د MS SQL سرور لپاره په C#.NET کې د LINQ پوښتنو د اصلاح کولو ځینې اړخونه

لکه څنګه چې تاسو د پایلو څخه لیدلی شئ، د ملیونونو ریکارډونو سره د دوه میزونو لپاره، د غوره شوي LINQ پوښتنه د غیر مطلوب شوي څخه څو چنده ګړندۍ ده.

په شرایطو کې د AND سره اختیار لپاره، د فورمې د لینک پوښتنه:

د 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

Add a comment