تنظیم عملکرد کوئری ها (1)

تنظیم عملکرد کوئری ها (1)

پیش از اینکه درخصوص بینه سازی کوئری ها در SQL  صحبت کنیم بهتر است با یک اصطلاح آشنا شویم. آرگومان های جستجوی یا SARG عبارت هایی هستند که برای محدود کردن تعداد رکوردهای بازگشتی از یک کوئری استفاده میشوند. معمولا زمانی که یک ستون از جداول در داخل یک Function و یا عبارتی دیگر بکار گرفته میشه مانند LEFT(Name,1)=’A’  به عنوان یک محدود کننده یا SARG شناخته نمیشن. اگر یک کوئری شامل SARG نباشد برای برگشت نتایج آن کوئری ، جدول مربوطه به روش Scan  پیمایش میشود.

در SQL  دو نوع پیمایش جداول وجود دارد

1.Scan که تمام جدول پیمایش میشود

2. Seek  که فقط قسمت مورد نظر را پیمایش میکنیم

همونطور که مشخص هست عملیات Seek  بهینه تر است.

برای مثال کوئری زیر را در نظر بگیرید

User AdvantureWorks

Create NONCLUSTERED INDEX OrderDataIndex

               On Sales.SalesOrderHeader(OrderDate);

Select Count(*) from sales.salesOrderHeader

               Where YEAR(OrderDate)= 2004

از انجایی که در این کوئری هیچ SARG ی استفاده نشده است پس از روش Scan برای پیمایش جداول استفاده میشود.

حال میتوان کوئری بالا را بدین شکل بهینه تر کرد

User AdvantureWorks

Create NONCLUSTERED INDEX OrderDataIndex

               On Sales.SalesOrderHeader(OrderDate);

Select Count(*) from sales.salesOrderHeader

               Where OrderDate>= ‘20040101’ and OrderDate<= ‘20050101’

با استفاده از کلیدهای ترکیبی Cntrl+M متوانید  Execution Plane مربوط به اجرای هر دو کوئری را مشاهده کنید و خواهید دید که هزینه اجرای کوئری دوم به مراتب بهتر از کوئری اول است.

استفاده از JOIN

برای بهینه سازی کوئری ها یکی از اولین استراتژی هایی که بکار گرفته میشه کم کردن تعداد JOIN ها است. نکته دیگری که باید به آن توجه کرد این است که از میان Inner Join و Outer join ، Outer Join ها هزینه بیشتری نسبت به Inner Join  دارند چون فعالت بیشتری برای پیدا کردن سطرهای نابرابر در SQL  صرف میشود.

اگر در کوئری شما تنها از inner join  استفاده شده است بهتر است بدانید که  تفاوتی وجود ندارد در اینکه شرط inner join  را در On بنویسید و یا آنرا با Where  پیاده سازی کنید هردو از لحاظ زمان عملکرد یکسان هستند. بنابراین دو کوئری زیر از لحاظ بهینگی در شرایط یکسانی می باشند

--Query 1

Select p.productID, c.CategoryId

               From products inner join category on p.productid=c.productidref

               Where p.color=’blue’

--Query 2

Select p.productID, c.CategoryId

               From products inner join category on p.productid=c.productidref

               And  p.color=’blue’

کوئری های فرعی غیرمرتبط

Subquery های غیر مرتبط با کوئری اصلی تنهای یک بار اجرا میشوند  این کئوری ها سربار بسیار کمی هم دارند. برای مثال کوئری زیر تنها یکبار میانگین قیمت های را محاسبه میکند سپس مقدار محاسبه شده بعنوان پرارمتر در کوئری اصلی استفاده میشود.

SELECT

       p.ProductID,

       P.Name

             FROM products AS p

                    WHERE p.price>=(

                    SELECT AVG(p2.price) FROM products AS p2

                    )

کوئری های فرعی وابسته

 Subquery هایی که به نوعی به کوئری اصلی وابسته میشوند از لحاظ عملکرد همانند کوئری هایی هستند که با JOIN  و علمگر EXIST پیاده سازی شده باشند. برای نمونه به کوئری زیر دقت کنید

select p.productid,

       p.name from production.product as p

       where exists (

                           select * from sales.saleorderDetail as sod

                                 where sod.productid=p.productid)

این نوع از کوئری ها معمولا بخاطر کوئری داخلی که با کوئری اصلی در ارتباط است، نسبت به JOIN عملکرد ضعیفتری دارند. اگر تعداد رکوردها  زیاد باشد کاملا این موضوع مشخص میشود چرا که به ازای هر رکورد، کوئری داخلی اجرا خواهد شد.

بایید یک کوئری دیگر را بررسی کنیم. این کوئری 6244 رکورد بر میگرداند و شامل دو ساب کوئری مرتبط با ک.وری اصلی نیز هست که به ازای هر رکورد اجرا میشوند که در مجموعا 12448 میشود.

select soh.saleOrderId,

             soh.OrderDate,

             (select top(1) sod1.UnitPrice

                    from sales.SalesOrderDetail as sod1

                    where sod1.SaleOrderId=soh.SaleOrderId

                    order by sod1.OrderQTY DESC) as UnitPrice),

 

                    (select top(1) sod1.OrderQTY

                    from sales.SalesOrderDetail as sod1

                    where sod1.SaleOrderId=soh.SaleOrderId

                    order by sod1.OrderQTY DESC) as OrderQTY)

             from sales.salesOrderHeader as soh

             where soh.TerrritoryID=4

البته این کوئری دارای اشکالاتی نیز هست.مثل اینکه ممکن است یکی از دو ساب کوئری ها مقداری را برنگرداند درحالی کوئری دیگر مقدار داشته باشد. هزینه اجرای QUERY COST این کوئری حدودا 151 میشه. که البته میخواهیم با بهینه سازی آنرا کمتر کنیم

برای بهینه سازی این کوئری چند راه وجود دارد. یکی از راه ها استفاده از  APPLY هست و برای اینکه خروجی کوئری مانند کوئری قبل باشه باید از OUTER APPLY  استفاده کنیم.

select soh.saleOrderId,

             soh.OrderDate,

             a.*

            

             from sales.salesOrderHeader as soh

             outer apply(

             select top(1) sod.UnitPrice,

                                   sod.OrderQTY

                    from sod.saleOrderID=soh.SaleOrderID as sod

                    order by sod.OrderQTY  desc) as a

             where soh.TerrritoryID=4

حالا اگر هزینه کوئری را محاسبه کنیم میبنیم که هزینه کوئری تقریبا نصف شده است و به 76 رسیده است.

حالا میخواهیم پا را فراتر بزاریم و با استفاده از ROW_NUMBER کوئری را بهینه تر کنیم.  از CTE کمک میگیریم و کوئری را بصورت زیر بازنویسی میکنیم

with a as(

 

select

       soh.SaleORderID,

       soh.OrderDate,

       sod.UnitPrice,

       sod.OrderQTY,

       Row_Number() over(

                                        partition by soh.SaleOrderID

                                        order by sod.OrderQTY desc

                                        ) as RowNo

             from sale.SaleOrderDetail as sod

             inner join sales.SalesOrderHeader as soh

                    on sod.SaleOrderID=soh.SaleOrderID

                    where soh.TerritoryID=4

)

select a.SaleORderID,

             a.OrderDate,

             a.UnitPrice,

             a.OrderQTY

              from a where a.RowNo=1

با این روشی که بکار بردیم خواهیم دید که هزینه کوئری از 76 به 3.6 رسید و این شگفت انگیزه!

مرتضی جنگجو

برنامه نویس fullstack با بیش از 14 سال سابقه کار و همکاری در توسعه و پیاده سازی نرم افزارهای تحت وب با تکنولوژی Net. در شرکتهای بزرگ ایرانی، هلندی، فنلاندی و ترکیه

شبکه های اجتماعی نویسنده

دیدگاه کاربران