MS SQL சேவையகத்திற்கான C#.NET இல் LINQ வினவல்களை மேம்படுத்துவதற்கான சில அம்சங்கள்

ஒரு சக்திவாய்ந்த புதிய தரவு கையாளுதல் மொழியாக LINQ .NET ஐ உள்ளிட்டது. அதன் ஒரு பகுதியாக LINQ to SQL ஆனது ஒரு 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

இப்போது பின்வரும் ஸ்கிரிப்டை இயக்குவதன் மூலம் Ref அட்டவணையை நிரப்புவோம்:

ரெஃப் அட்டவணையை நிரப்புகிறது

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 மில்லியனுக்கும் அதிகமான வரிசை தரவுகளைக் கொண்டுள்ளது.

இப்போது விஷுவல் ஸ்டுடியோவில் நீங்கள் சோதனை விஷுவல் சி# கன்சோல் ஆப் (.NET Framework) திட்டத்தை உருவாக்க வேண்டும்:

MS SQL சேவையகத்திற்கான C#.NET இல் LINQ வினவல்களை மேம்படுத்துவதற்கான சில அம்சங்கள்

அடுத்து, தரவுத்தளத்துடன் தொடர்புகொள்வதற்கு, நிறுவன கட்டமைப்பிற்கான நூலகத்தைச் சேர்க்க வேண்டும்.
அதைச் சேர்க்க, திட்டத்தில் வலது கிளிக் செய்து சூழல் மெனுவிலிருந்து NuGet தொகுப்புகளை நிர்வகி என்பதைத் தேர்ந்தெடுக்கவும்:

MS SQL சேவையகத்திற்கான C#.NET இல் LINQ வினவல்களை மேம்படுத்துவதற்கான சில அம்சங்கள்

பின்னர், தோன்றும் NuGet தொகுப்பு மேலாண்மை சாளரத்தில், தேடல் சாளரத்தில் "Entity Framework" என்ற வார்த்தையை உள்ளிட்டு, Entity Framework தொகுப்பைத் தேர்ந்தெடுத்து அதை நிறுவவும்:

MS SQL சேவையகத்திற்கான C#.NET இல் LINQ வினவல்களை மேம்படுத்துவதற்கான சில அம்சங்கள்

அடுத்து, App.config கோப்பில், configSections உறுப்பை மூடிய பிறகு, நீங்கள் பின்வரும் தொகுதியைச் சேர்க்க வேண்டும்:

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

connectionString இல் நீங்கள் இணைப்பு சரத்தை உள்ளிட வேண்டும்.

இப்போது தனித்தனி கோப்புகளில் 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. 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; }
        }
    }
    

இப்போது தனி கோப்பில் பயனர் சூழல் சூழலை உருவாக்குவோம்:

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 வினவலை உருவாக்கியது.

இப்போது 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 வினவல்களை மேம்படுத்துவதற்கான சில அம்சங்கள்
, இரண்டு தொகுப்புகளின் (அட்டவணைகள்) கார்ட்டீசியன் தயாரிப்பு மூலம் தேர்வு நிகழ்கிறது என்பதை நீங்கள் உறுதிசெய்யலாம்:

உருவாக்கப்பட்ட 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. INNER JOIN-UNION க்கு சராசரி செயலாக்க நேரம் 24 வினாடிகளுக்கும் குறைவாக உள்ளது:
    MS SQL சேவையகத்திற்கான C#.NET இல் LINQ வினவல்களை மேம்படுத்துவதற்கான சில அம்சங்கள்

நீங்கள் முடிவுகளில் இருந்து பார்க்க முடியும் என, மில்லியன் கணக்கான பதிவுகளைக் கொண்ட இரண்டு அட்டவணைகளுக்கு, மேம்படுத்தப்பட்ட LINQ வினவல், மேம்படுத்தப்படாததை விட பல மடங்கு வேகமானது.

மற்றும் நிபந்தனைகளில் உள்ள விருப்பத்திற்கு, படிவத்தின் 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 வினவல் (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;
}

எனவே, MS SQL சேவையகத்திற்கு LINQ வினவல்களை மேம்படுத்துவதில் சில அம்சங்களை ஆய்வு செய்தோம்.

துரதிர்ஷ்டவசமாக, அனுபவம் வாய்ந்த மற்றும் முன்னணி .NET டெவலப்பர்கள் கூட, திரைக்குப் பின்னால் தாங்கள் பயன்படுத்தும் வழிமுறைகள் என்ன செய்கின்றன என்பதைப் புரிந்து கொள்ள வேண்டும் என்பதை மறந்து விடுகிறார்கள். இல்லையெனில், அவை கட்டமைப்பாளர்களாக மாறும் மற்றும் எதிர்காலத்தில் மென்பொருள் தீர்வை அளவிடும் போது மற்றும் வெளிப்புற சுற்றுச்சூழல் நிலைமைகளில் சிறிய மாற்றங்களுடன் ஒரு நேர வெடிகுண்டை நிறுவலாம்.

ஒரு சிறு ஆய்வும் நடத்தப்பட்டது இங்கே.

சோதனைக்கான ஆதாரங்கள் - திட்டமே, TEST தரவுத்தளத்தில் அட்டவணைகளை உருவாக்குதல், அத்துடன் இந்த அட்டவணைகளை தரவுகளுடன் நிரப்புதல் ஆகியவை அமைந்துள்ளன. இங்கே.
இந்த களஞ்சியத்தில், திட்டங்கள் கோப்புறையில், அல்லது நிபந்தனைகளுடன் வினவல்களை இயக்குவதற்கான திட்டங்கள் உள்ளன.

ஆதாரம்: www.habr.com

கருத்தைச் சேர்