SQL Tips: Tối ưu hóa câu lệnh MySQL - Phần 2

Tiếp phần 1 đã viết được khá lâu. Nay chúng ta sẽ tiếp tục viết phần 2 trong loạt bài tối ưu hóa câu lệnh MySQL

Vấn đề dư thừa dữ liệu trong câu truy vấn

Một nguyên tắc đơn giản nhất khi truy vấn dữ liệu là tránh sử dụng SELECT * trong bất kỳ trường hợp nào. Vì khi gọi lệnh này thì hệ quản trị sẽ tốn thêm tài nguyên để định danh những cột sẽ được lấy ra. Hãy chỉ rõ cột nào mình muốn lấy ra, giảm tải cho hệ thống và câu lệnh trở nên sáng sủa hơn.

Trong câu lệnh JOIN nhiều bảng thì cũng có chuyện dư thừa dữ liệu trong câu join. Bạn tìm hiểu thêm về tích descartes trong SQL thì bạn sẽ hiểu rõ hơn phần này. ví dụ đơn giản dưới đây:

VD

Bảng đơn hàng tb_Order có 300 bản ghi.

Bảng người mua tb_User có 1.000.000 bản ghi.

Bảng công ty tb_Company có 100.000 bản ghi.

Bạn cần lấy thông tin bản ghi thông tin mã hóa đơn, tài khoản người mua, tên người mua, tuổi, tên công ty của những khách hàng lớn hơn 18 tuổi trong năm 2021. 

Giả sử người dùng có thể thuộc hoặc không thuộc công ty nào cả. Ta sẽ phải viết query sử dụng câu lệnh JOIN như sau:

Select  a.OrderNumber,

                a.OrderDate, 

b.UserName,

b.FullName,

b.Age, 

c.CompanyName

from  tb_Order as a 

inner join   tb_User as b

on  a.UserID = b.UserID

left join tb_Company as c

on  b.CompanyID = c.CompanyID

where  b.Age > 18   

and a.OrderDate >= '202-01-01' and  a.OrderDate <= '202-12-31'


Nhìn câu lệnh này thì sau khi Join bảng a, b lại, số bản ghi câu lệnh phải duyệt ở mệnh đề where là  

300 * 1.000.000 = 30.000.000 bản ghi. Để giảm bớt số bản ghi lọc bởi where thì chúng ta nên viết lại thế này sẽ tối ưu hơn:

Select  a.OrderNumber,

                a.OrderDate, 

b.UserName,

b.FullName,

b.Age, 

c.CompanyName

from  tb_Order as a 

inner join   tb_User as b

on  a.UserID = b.UserID

and b.Age > 18   

left join tb_Company as c

on  b.CompanyID = c.CompanyID

where   a.OrderDate >= '202-01-01' and  a.OrderDate <= '202-12-31'


Trong một số trường hợp mà Left join thêm 1 loạt bảng khác để lấy thông tin thêm trên SELECT mà trong điều kiện WHERE không chứa điều kiện của bảng đó thì ta có thể viết dạng subquery để tăng tốc độ cho câu query. Chẳng hạn câu query:

Select  top 50 a.OrderNumber,

               a.OrderDate, 

b.UserName,

b.FullName,

b.Age, 

c.CompanyName,

d.CityName as CompanyCityName

from  tb_Order as a 

inner join   tb_User as b

on  a.UserID = b.UserID

and b.Age > 18   

left join tb_Company as c

on  b.CompanyID = c.CompanyID

left join tb_City as d

on d.CityID  = c.CityID

where   a.OrderDate >= '202-01-01' and  a.OrderDate <= '202-12-31'


Câu lệnh này nếu rơi vào trường hợp bảng Company và bảng City có rất nhiều dữ liệu (từ triệu bản ghi trở lên) sẽ chạy chậm hơn câu lệnh sau:

 select  ab.OrderNumber,

               ab.OrderDate, 

ab.UserName,

ab.FullName,

ab.Age,

c.CompanyName,

d.CityName as CompanyCityName

from (

Select  a.OrderNumber,

a.OrderDate, 

b.UserName,

b.FullName,

b.Age, 

b.CompanyID

from  tb_Order as a 

inner join   tb_User as b

on  a.UserID = b.UserID

and b.Age > 18   

where  a.OrderDate >= '202-01-01' and  a.OrderDate <= '202-12-31' 

                  order by a.OrderDate desc

                  limit 50 

) as ab

left join tb_Company as c

on  c.CompanyID = ab.CompanyID

left join tb_City as d

on d.CityID  = c.CityID


0 comments:

Đăng nhận xét

Có nhận xét mới

Like