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