አንዳንድ የLINQ መጠይቅ ማሻሻያ ገፅታዎች በC#.NET ለMS SQL አገልጋይ

LINQ NET እንደ ኃይለኛ አዲስ የውሂብ ማጭበርበር ቋንቋ አስገብቷል። ከ LINQ ወደ SQL እንደ አንድ አካል ከዲቢኤምኤስ ጋር በተመጣጣኝ ሁኔታ እንዲገናኙ ይፈቅድልዎታል፣ ለምሳሌ የEntity Framework። ነገር ግን፣ ብዙ ጊዜ ሲጠቀሙበት፣ ገንቢዎች ምን አይነት የSQL መጠይቅ እንደሚያመነጩ፣ በእርስዎ ሁኔታ፣ አካል መዋቅር የሚለውን መመልከት ይረሳሉ።

ሁለት ዋና ዋና ነጥቦችን በምሳሌ እንመልከት።
ይህንን ለማድረግ በ SQL Server ውስጥ የውሂብ ጎታ ሙከራን እንፈጥራለን, እና በውስጡም የሚከተለውን መጠይቅ በመጠቀም ሁለት ጠረጴዛዎችን እንፈጥራለን.

ጠረጴዛዎችን መፍጠር

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 ሚሊዮን በላይ ረድፎች አሉት.

አሁን በ Visual Studio ውስጥ፣ የሙከራ Visual C# Console መተግበሪያ (.NET Framework) ፕሮጀክት መፍጠር አለቦት፡-

አንዳንድ የLINQ መጠይቅ ማሻሻያ ገፅታዎች በC#.NET ለMS SQL አገልጋይ

በመቀጠል ከመረጃ ቋቱ ጋር መስተጋብር ለመፍጠር ለድርጅት መዋቅር ቤተ-መጽሐፍት ማከል ያስፈልግዎታል።
እሱን ለመጨመር በፕሮጄክቱ ላይ በቀኝ ጠቅ ያድርጉ እና ከአውድ ምናሌው ውስጥ ኑግት ፓኬጆችን አስተዳድርን ይምረጡ።

አንዳንድ የLINQ መጠይቅ ማሻሻያ ገፅታዎች በC#.NET ለMS SQL አገልጋይ

ከዚያም በሚታየው የኑጌት የጥቅል አስተዳደር መስኮት በፍለጋ ሳጥኑ ውስጥ "Entity Framework" የሚለውን ቃል አስገባ እና የEntity Framework ጥቅልን ምረጥና ጫን።

አንዳንድ የLINQ መጠይቅ ማሻሻያ ገፅታዎች በC#.NET ለMS SQL አገልጋይ

በመቀጠል በ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 ቤዝ ክፍል እንፈጥራለን፣ እሱም የጋራ መስኮችን ያካትታል፡

የመሠረት ክፍል 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; }
        }
    }
    

አሁን በተለየ ፋይል ውስጥ የተጠቃሚ ኮንቴክስት አውድ እንፍጠር፡-

የተጠቃሚ ኮንቴክስ ክፍልን መተግበር

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; }
    }
}

የማመቻቸት ሙከራዎችን ከ LINQ ወደ SQL በEF ለMS SQL አገልጋይ ለማካሄድ ዝግጁ የሆነ መፍትሄ አግኝተናል፡

አንዳንድ የLINQ መጠይቅ ማሻሻያ ገፅታዎች በC#.NET ለMS SQL አገልጋይ

አሁን በ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 መጠይቁ የSQL ጥያቄን ለኤምኤስ SQL አገልጋይ DBMS በጥሩ ሁኔታ ፈጥሯል።

አሁን በ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 ሰከንድ በላይ ከትዕዛዙ አፈጻጸም ጊዜ ጋር በተዛመደ ስህተት ይሰናከላል።

አንዳንድ የLINQ መጠይቅ ማሻሻያ ገፅታዎች በC#.NET ለMS SQL አገልጋይ

የትኛው ጥያቄ በLINQ እንደተፈጠረ ከተመለከቱ፡-

አንዳንድ የLINQ መጠይቅ ማሻሻያ ገፅታዎች በC#.NET ለMS SQL አገልጋይ
, ከዚያም ምርጫው በሁለት ስብስቦች (ጠረጴዛዎች) የካርቴዥያን ምርት በኩል መከሰቱን ማረጋገጥ ይችላሉ.

የተፈጠረ የ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 ሰከንድ ነው።
    አንዳንድ የLINQ መጠይቅ ማሻሻያ ገፅታዎች በC#.NET ለMS SQL አገልጋይ
  2. ለ INER JOIN-UNION አማካኝ የማስፈጸሚያ ጊዜ ከ24 ሰከንድ በታች ነው።
    አንዳንድ የLINQ መጠይቅ ማሻሻያ ገፅታዎች በC#.NET ለMS SQL አገልጋይ

ከውጤቶቹ ማየት እንደምትችለው፣ ለሁለት ሰንጠረዦች በሚሊዮን የሚቆጠሩ መዝገቦች፣ የተመቻቸ የ 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 ሰከንድ ውስጥ ይሰራል፡

አንዳንድ የLINQ መጠይቅ ማሻሻያ ገፅታዎች በC#.NET ለMS SQL አገልጋይ
እንዲሁም ለ LINQ ከሚከተለው ጥያቄ ይልቅ ማጭበርበርን ይቃወማል፡-

የ LINQ ጥያቄ (1 ኛ አማራጭ)

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 ጥያቄ (2 ኛ አማራጭ)

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;
}

ስለዚህ፣ የLINQ መጠይቆችን ወደ MS SQL አገልጋይ በማሳደግ ረገድ አንዳንድ ገጽታዎችን መርምረናል።

በሚያሳዝን ሁኔታ, ልምድ ያላቸው እና መሪ የ NET ገንቢዎች እንኳን የሚጠቀሙባቸው መመሪያዎች ከትዕይንቱ በስተጀርባ ምን እንደሚሰሩ መረዳት እንዳለባቸው ይረሳሉ. አለበለዚያ የሶፍትዌር መፍትሄን በሚቀንሱበት ጊዜ እና በውጫዊ የአካባቢ ሁኔታዎች ላይ ጥቃቅን ለውጦች ሲደረጉ, አወቃቀሮች ይሆናሉ እና ለወደፊቱ ጊዜ ቦምብ መትከል ይችላሉ.

አጭር ግምገማም ተካሂዷል እዚህ.

የፈተናው ምንጮች - ፕሮጀክቱ ራሱ, በ TEST የውሂብ ጎታ ውስጥ ሠንጠረዦችን መፍጠር, እንዲሁም እነዚህን ሠንጠረዦች በመረጃ መሙላት ይገኛሉ. እዚህ.
እንዲሁም በዚህ ማከማቻ ውስጥ በፕላኖች አቃፊ ውስጥ ከOR ሁኔታዎች ጋር መጠይቆችን የማስፈጸሚያ እቅዶች አሉ።

ምንጭ: hab.com

አስተያየት ያክሉ