دوره آموزشی Entity FrameWork Core - قسمت دوازدهم

دوره آموزشی Entity FrameWork Core - قسمت يازدهمخوب اجازه بدهید قبل از شروع مفهوم شاخص ها در Entity framework Core با انواع شاخص ها در یک پایگاه داده رابطه ای ماننده sql server آشنا شویم تا با درک بهتر به سراغ موضوع اصلی خود برویم.شاخص های پایگاه داده برای بهبود سرعت عملیات پایگاه داده در جدولی با تعداد رکورد زیاد استفاده می شود. به عنوان مثال فهرست یک کتاب به شما امکان می دهد مستقیماً به موضوعات مختلف مورد بحث در کتاب بروید. اگر می خواهید موضوع خاصی را جستجو کنید، فقط به فهرست بروید، شماره صفحه ای را پیدا کنید که حاوی موضوع مورد نظر شما است و سپس می توانید مستقیماً به آن صفحه بروید. بدون فهرست، باید کل کتاب را جستجو کنید.شاخص های پایگاه داده به همین ترتیب کار می کنند. بدون ایندکس، برای انجام یک عملیات پایگاه داده خاص، باید کل جدول را جستجو کنید. با ایندکس ها، لازم نیست تمام رکوردهای جدول را اسکن کنید. ایندکس شما را مستقیماً به رکوردی که در جستجوی آن هستید ارجاع می دهد و زمان اجرای پرس و جو را به میزان قابل توجهی کاهش می دهد.شاخص های SQL Server را می توان به دو نوع اصلی تقسیم کرد:شاخص های خوشه ای(Clustered Indexes)شاخص های غیر خوشه ای(Non-Clustered Indexes)شاخص های خوشه ای(Clustered Indexes) :ایندکس خوشه ای شاخصی است که ترتیب فیزیکی ذخیره رکوردهای جدول در پایگاه داده را مشخص می کند. از آنجایی که تنها یک روش می تواند وجود داشته باشد که در آن رکوردها به صورت فیزیکی در یک جدول پایگاه داده ذخیره شوند، در هر جدول فقط یک شاخص خوشه ای وجود دارد. به طور پیش فرض یک شاخص خوشه ای بر روی یک ستون کلید اصلی(primary key ) ایجاد می شود.بیایید یک جدول فرضی با ستون کلید اصلی ایجاد کنیم تا شاخص خوشه‌ای پیش‌فرض را ببینیم. اسکریپت زیر را اجرا کنید:CREATE DATABASE TestIndex CREATE TABLE Person( id INT PRIMARY KEY, name VARCHAR(100) NOT NULL, family VARCHAR(100) NOT NULL, age INT NOT NULL )هنگامی که اسکریپت بالا اجرا می شود، یک شاخص خوشه ای به طور خودکار در ستون id ایجاد می شود. برای مشاهده تمام شاخص ها در یک جدول، می توانید از stored procedure با نام “sp_helpindex” استفاده کنید:USE TestIndex EXECUTE sp_helpindex Personاگر یک رکورد جدید به جدول person اضافه کنید، به ترتیب صعودی مقدار در ستون id ذخیره می شود. اگر اولین رکوردی که در جدول وارد می‌کنید دارای شناسه مثلا 4 باشد ، رکورد به جای ردیف اول در ردیف چهارم ذخیره می‌شود زیرا شاخص یا بهتر بگوییم فهرست خوشه‌ای نظم فیزیکی را حفظ می‌کند.شما می توانید شاخص های خوشه ای، سفارشی خود را ایجاد کنید. تا اینجا ما یک شاخص خوشه‌بندی شده به دلیل ستون کلید اولیه داریم. اگر محدودیت کلید اصلی(primary key constraint) را حذف کنیم، خوشه پیش فرض حذف خواهد شد. اسکریپت زیر محدودیت کلید اصلی را حذف می کند.USE TestIndex ALTER TABLE Person DROP CONSTRAINT PK__Person__3213E83FD96E8679 GOاسکریپت زیر یک شاخص سفارشی "IX_tblPerson_Age" در ستون سن جدول person ایجاد می کند. با توجه به این شاخص، تمام رکوردهای جدول person به ترتیب افزایش سن ذخیره می شود.use TestIndex CREATE CLUSTERED INDEX IX_tblPerson_Age ON Person(age ASC)با اجرای اسکریپت زیر خواهیم داشت :USE TestIndex EXECUTE sp_helpindex Personحال بیایید چند رکورد ساختگی در جدول Person اضافه کنیم تا ببینیم آیا واقعاً به ترتیب سنی درج شده اند یا خیر:USE TestIndex INSERT INTO Person VALUES (1, 'farshid', 'azizi', 39), (2, 'reza', 'Aghaee', 20), (3, 'mitra', 'Rasti', 54), (4, 'zahra', 'hashemee', 10), (5, 'Nick', 'peterson', 29)در اسکریپت بالا 5 رکورد ساختگی اضافه می کنیم. به مقادیر ستون سن توجه کنید. آنها مقادیر تصادفی دارند و در هیچ ترتیب منطقی نیستند. با این حال، از آنجایی که ما یک شاخص خوشه ای ایجاد کرده ایم، رکوردها در واقع به ترتیب صعودی مقدار در ستون age درج می شوند. می‌توانید با انتخاب تمام رکوردها از جدول person، این موضوع را تأیید کنید.SELECT * FROM Personمی بینید که رکوردها به ترتیب صعودی مقادیر در ستون سن مرتب شده اند.شاخص های غیر خوشه ای(Non-Clustered Indexes) :یک شاخص غیر خوشه ای نیز برای سرعت بخشیدن به عملیات جستجو استفاده می شود. برخلاف شاخص های خوشه ای، یک شاخص غیر خوشه ای به صورت فیزیکی ترتیب درج رکوردها در جدول را مشخص نمی کند. در واقع یک شاخص غیر خوشه ای در مکانی جدا از جدول داده ها ذخیره می شود. شاخص غیر خوشه ای مانند فهرست کتاب است که جدا از مطالب اصلی کتاب قرار دارد. از آنجایی که نمایه های غیر خوشه ای در یک مکان جداگانه قرار دارند، می تواند چندین شاخص غیر خوشه ای در هر جدول وجود داشته باشد.برای ایجاد یک شاخص غیر خوشه ای، باید از عبارت "CREATE NONCLUSTERED" استفاده کنید. بقیه syntax مانند syntax برای ایجاد یک نمایه خوشه ای باقی می ماند. اسکریپت زیر یک شاخص غیر خوشه‌بندی شده «IX_tblPerson_Name» ایجاد می‌کند که رکوردها را به ترتیب صعودی نام مرتب می‌کند.use TestIndex CREATE NONCLUSTERED INDEX IX_tblPerson_Name ON Person(name ASC)USE TestIndex select name,Address as 'Record Address' from Personدر اینجا، "Address " در هر ردیف اشاره ای به رکوردهای جدول Person با نام های مربوطه است.برای مثال، اگر می‌خواهید آدرس شخصی به نام «reza» را بازیابی کنید، پایگاه داده ابتدا «reza» را در فهرست غیر خوشه‌ای «IX_tblPerson_Name» جستجو می‌کند و از فهرست غیر خوشه‌ای، رفرنس رکورد را دریافت می‌کند. و از آن برای برگرداندن سن شخص به نام "reza" استفاده خواهد کرد.از آنجایی که یک پایگاه داده باید دو جستجو انجام دهد، ابتدا در فهرست غیر خوشه ای و سپس در جدول واقعی، شاخص های غیر خوشه ای می توانند برای عملیات جستجو کندتر باشند. با این حال، برای عملیات INSERT و UPDATE، شاخص های غیر خوشه ای سریعتر هستند زیرا ترتیب رکوردها فقط باید در فهرست به روز شوند و نه در جدول واقعی.زمان استفاده از شاخص های خوشه ای یا غیر خوشه ای :اکنون که تفاوت‌های بین شاخص خوشه‌ای و غیر خوشه‌ای را می‌دانید، بیایید سناریوهای مختلف برای استفاده از هر یک از آنها را ببینیم.تعداد شاخص هااین کاملا واضح است. اگر نیاز به ایجاد چندین شاخص در پایگاه داده خود دارید، به سراغ شاخص غیر خوشه ای بروید زیرا تنها یک شاخص خوشه ای در هر جدول می تواند وجود داشته باشد.عملیات SELECTدر اینجا شاخص های غیر خوشه ای سریعتر هستند. به عنوان مثال، اگر یک شاخص در ستون "name" ایجاد کرده اید و می خواهید فقط name را انتخاب کنید، شاخص های غیر خوشه ای به سرعت بیشتری نام را برمی گردانند.با این حال، اگر بخواهید با استفاده از شاخص نام، سایر مقادیر ستون مانند سن و ... را انتخاب کنید، عملیات SELECT کندتر خواهد بود زیرا ابتدا نام از فهرست جستجو می شود و سپس از ارجاع به رکورد واقعی جدول برای جستجو استفاده می شود. از سوی دیگر، با شاخص‌های خوشه‌بندی‌شده از آنجایی که همه رکوردها از قبل مرتب شده‌اند، اگر داده‌ها از ستون‌هایی غیر از ستون با شاخص خوشه‌ای انتخاب شوند، عملیات SELECT سریع‌تر است.عملیات INSERT/UPDATEعملیات INSERT و UPDATE با شاخص های غیر خوشه ای سریعتر هستند، زیرا هنگام انجام عملیات INSERT یا UPDATE نیازی به مرتب سازی رکوردهای واقعی نیست. بلکه فقط شاخص غیر خوشه ای نیاز به به روز رسانی دارد.فضای دیسکاز آنجایی که شاخص های غیر خوشه ای در مکانی جداگانه نسبت به جدول اصلی ذخیره می شوند، شاخص های غیر خوشه ای فضای دیسک اضافی را مصرف می کنند. اگر فضای دیسک مشکل دارد، از یک شاخص خوشه ای استفاده کنید. حکم نهاییبه عنوان یک قانون سرانگشتی، هر جدول باید حداقل یک شاخص خوشه‌بندی شده در ستونی داشته باشد که برای انتخاب(Select) رکوردها استفاده می‌شود و حاوی مقادیر منحصربه‌فرد است. ستون کلید اولیه یک کاندید ایده آل برای یک شاخص خوشه ای است.از سوی دیگر، ستون هایی که اغلب در پرس و جوهای INSERT و UPDATE درگیر می شوند، باید یک شاخص غیر خوشه ای داشته باشند، با این فرض که فضای دیسک محدودیتی نداشته باشد.خوب با این مقدمه و درک مفهوم شاخص ها(Clustered و nonclustered) در یک پایگاه داده رابطه ای به سراغ ادامه مطلب در ef Core می رویم.شاخص ها (Indexes) در EF Core: همانطور که گفتیم شاخص ها یک مفهوم رایج در بسیاری از Data Storeها است. در حالی که پیاده سازی آنها در Data Storeها ممکن است متفاوت باشد، از آنها برای کارآمدتر کردن جستجوهای مبتنی بر یک ستون (یا مجموعه ای از ستون ها) استفاده می شود. شما می توانید یک شاخص را روی یک ستون به صورت زیر مشخص کنید:با استفاده از Data Annotations :[Index(nameof(Url))] public class Blog { public int BlogId { get; set; } public string Url { get; set; } }با استفاده از Fluent API : protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>() .HasIndex(b => b.Url); }طبق قرارداد، در هر ویژگی (یا مجموعه ای از ویژگی ها) که به عنوان کلید خارجی استفاده می شود، یک شاخص ایجاد می شود.EF Core تنها از یک شاخص در هر مجموعه مشخصی از ویژگی ها پشتیبانی می کند. اگر Index ای را روی مجموعه ای از ویژگی ها پیکربندی کنید که قبلاً دارای یک Index تعریف شده است، چه بر اساس قرارداد یا پیکربندی دیگر، آنگاه تعریف آن Index را تغییر خواهید داد. اگر بخواهید ویژگی یا پراپرتی ای را که بر اساس قرارداد ایجاد شده است پیکربندی کنید، این کار مفید است.با دیدن تصویر فوق و توضیحات مقدماتی متوجه خواهید شد طبق قرارداد BlogId کلید اولیه ، شاخص منحصر به فرد و شاخص خوشه ای(Clustered Indexe) می باشد. همانطور که مشخص است url یک شاخص غیر خوشه ای(Non-Clustered Indexs) است اما منحصر به فرد نیست!شاخص ترکیبی (Composite index) :یک شاخص همچنین می تواند بیش از یک ستون را شامل شود:با استفاده از Data Annotations :[Index(nameof(FirstName), nameof(LastName))] public class Person { public int PersonId { get; set; } public string FirstName { get; set; } public string LastName { get; set; } }با استفاده از Fluent API : protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Person>() .HasIndex(p => new { p.FirstName, p.LastName }); }ایندکس‌ روی ستون‌های متعدد، که به‌عنوان Composite index نیز شناخته می‌شوند، پرس‌وجوهایی را که روی ستون‌های شاخص شده فیلتر می‌شوند، سرعت می‌بخشند.منحصر به فرد بودن شاخص (Index uniqueness) :به‌طور پیش‌فرض، شاخص‌ها منحصربه‌فرد نیستند: چندین ردیف مجاز هستند که مقدار(های) یکسانی برای مجموعه ستون‌های شاخص داشته باشند. شما می توانید یک شاخص را به صورت زیر منحصر به فرد کنید:با استفاده از Data Annotations :[Index(nameof(Url), IsUnique = true)] public class Blog { public int BlogId { get; set; } public string Url { get; set; } }با استفاده از Fluent API : protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>()= .HasIndex(b => b.Url) .IsUnique(); }تلاش برای درج بیش از یک موجودیت با مقادیر یکسان برای مجموعه ستون های شاخص، باعث ایجاد یک استثنا می شود.ترتیب مرتب سازی شاخص (Index sort order) :این ویژگی در EF Core 7.0 معرفی خواهد شد.در اکثر پایگاه های داده، هر ستونی که توسط یک index پوشش داده می شود، می تواند صعودی یا نزولی باشد. برای شاخص هایی که فقط یک ستون را پوشش می‌دهند، این معمولاً مهم نیست: پایگاه داده می‌تواند در صورت نیاز، شاخص ها را به ترتیب معکوس طی کند. با این حال، برای شاخص های ترکیبی، ترتیب می تواند برای عملکرد خوب بسیار مهم باشد و می تواند به معنای تفاوت بین استفاده از یک شاخص توسط یک پرس و جو باشد یا نه. به طور کلی، ترتیب‌های مرتب‌سازی ستون‌های Index باید با مواردی که در عبارت ORDER BY درخواست شما مشخص شده است مطابقت داشته باشد.ترتیب مرتب سازی شاخص به طور پیش فرض صعودی است. به صورت زیر می‌توانید تمام ستون‌ها را نزولی کنید:با استفاده از Data Annotations :[Index(nameof(Url), nameof(Rating), AllDescending = true)] public class Blog { public int BlogId { get; set; } public string Url { get; set; } public int Rating { get; set; } }با استفاده از Fluent API : protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>() .HasIndex(b => new { b.Url, b.Rating }) .IsDescending(); }همچنین می توانید ترتیب مرتب سازی را بر اساس ستون به ستون به صورت زیر مشخص کنید:با استفاده از Data Annotations :[Index(nameof(Url), nameof(Rating), IsDescending = new[] { false, true })] public class Blog { public int BlogId { get; set; } public string Url { get; set; } public int Rating { get; set; } }با استفاده از Fluent API : protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>() .HasIndex(b => new { b.Url, b.Rating }) .IsDescending(false, true); }نام شاخص (Index name) :طبق قرارداد، شاخص های ایجاد شده در پایگاه داده رابطه ای IX_<type name>_<property name> نامیده می شوند. برای شاخص های ترکیبی، <property name> به فهرستی از نام‌های جدا شده با underscore تبدیل می‌شود.می توانید نام شاخص ایجاد شده در پایگاه داده را پیکربندی کنید:با استفاده از Data Annotations :[Index(nameof(Url), Name = &quotIndex_Url&quot)] public class Blog { public int BlogId { get; set; } public string Url { get; set; } }با استفاده از Fluent API :protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>() .HasIndex(b => b.Url) .HasDatabaseName(&quotIndex_Url&quot); } اعمال فیلتر بر روی شاخص (Index filter) :برخی از پایگاه های داده رابطه ای به شما امکان می دهند یک شاخص فیلتر شده را مشخص کنید. این به شما امکان می دهد فقط زیر مجموعه ای از مقادیر یک ستون را index کنید، اندازه شاخص را کاهش داده و عملکرد و استفاده از فضای دیسک را بهبود می بخشد. یک شاخص فیلتر شده با طراحی خوب می تواند عملکرد پرس و جو را بهبود بخشدمی‌توانید از Fluent API برای تعیین فیلتر روی یک شاخص استفاده کنید، که به عنوان SQL expression ارائه می‌شود:protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>() .HasIndex(b => b.Url) .HasFilter(&quot[Url] IS NOT NULL&quot); }هنگام استفاده از ارائه‌دهندهSQL Server ـ EF یک فیلتر «IS NOT NULL» برای تمام ستون‌های nullable که بخشی از یک شاخص منحصر به فرد(unique index) هستند، اضافه می‌کند. برای نادیده گرفتن این قرارداد می توانید یک مقدار تهی(null) ارائه کنید.protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>() .HasIndex(b => b.Url) .IsUnique() .HasFilter(null); }شاخص های Included columns:برخی از پایگاه‌های داده رابطه‌ای به شما اجازه می‌دهند مجموعه‌ای از ستون‌ها را پیکربندی کنید که در فهرست(شاخص ) گنجانده می‌شوند، اما بخشی از "کلید" آن نیستند. این می تواند عملکرد پرس و جو را به طور قابل توجهی بهبود بخشد زمانی که تمام ستون های پرس و جو به عنوان ستون های کلیدی یا غیر کلیدی در فهرست گنجانده شوند، زیرا خود جدول نیازی به دسترسی ندارد. در مثال زیر، ستون Url بخشی از index key است، بنابراین هرگونه فیلترینگ پرس و جو در آن ستون می تواند از ایندکس استفاده کند. اما علاوه بر این، جستجوهایی که فقط به ستون‌های Title و PublishedOn دسترسی دارند، نیازی به دسترسی به جدول ندارند و کارآمدتر اجرا می‌شوند:protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Post>() .HasIndex(p => p.Url) .IncludeProperties( p => new { p.Title, p.PublishedOn }); }بررسی محدودیت ها(Check constraints) :بررسی محدودیت‌ها یا همان Check constraints یک ویژگی relational استاندارد است که به شما امکان می‌دهد شرایطی را تعریف کنید که باید برای همه ردیف‌های یک جدول برقرار باشد. هر تلاشی برای درج یا تغییر داده هایی که محدودیت را نقض کند با شکست مواجه خواهد شد. Check constraints شبیه به محدودیت‌های غیر تهی (که تهی‌ها را در یک ستون ممنوع می‌کنند) یا محدودیت‌های منحصربه‌فرد (که تکرارها را ممنوع می‌کنند) هستند، اما اجازه می‌دهند تا عبارت SQL دلخواه تعریف شود.شما می توانید از Fluent API برای تعیین یک Check constraints در جدول استفاده کنید که به عنوان عبارت SQL ارائه می شود:protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Product>() .HasCheckConstraint(&quotCK_Prices&quot, &quot[Price] > [DiscountedPrice]&quot, c => c.HasName(&quotCK_Product_Prices&quot)); }بیشتر بخوانید : دوره آموزشی Entity FrameWork Core - قسمت سیزدهمبیشتر بخوانید : دوره آموزشی Entity FrameWork Coreبیشتر بخوانید : نقشه راه توسعه دهندگان Asp.NET Corehttps://zarinp.al/farshidazizi