CHƯƠNG 2 : PHÂN RÃ VẤN TIN VÀ CỤC BỘ HÓA DỮ LIỆU
3.1. Ứng dụng trong xử lý dữ liệu học tập tại trường cao đẳng kỹ thuật Viêng
3.1.1. Lý thuyết và kỹ thuật trong các câu lệnh
3.1.1.1. Các nguyên nhân làm chậm quá trình xữ lý truy vấn
Một số nguyên nhân làm cho hệ thống khi xử lý truy xuất thông tinkém hiệu quả, tốn thời gian và bộ nhớ:
1. Do tài nguyên phần cứng:
- Không có hay thiếu tận dụng được lưu lượng cổng I/O - Thiếu bộ nhớ vật lý.
- Kết nối mạng chậm.
2. Do thực thi câu lệnh trên phần cứng
- Không có hay thiếu sử dụng các lợi ích của Indexes.
- Các câu truy vấn Transact-SQL chuyển số lượng dữ liệu lớn từ server đến client.
- Thực hiện các câu truy vấn OLTP (Online Transaction Procesing) and OLAP (Online Analytical Procesing) trên cùng 1 máy server.
-Trả về các dữ liệu không cần thiết. - Các câu truy vấn được viết chưa tối ưu.
3. Do các câu lệnh truy vấn
Do tài nguyên phần cứng hạn chế, chúng ta phải tìm giải pháp xử lý khắc phục bằng việc xử lý các câu lệnh SQL.Các trường hợp cụ thể và các giải pháp tối ưu được đưa ra như sau:
- Trong câu SELECT, nếu không sử dụng mệnh đề WHERE thì SQL Server sẽ thực hiện việc quét toàn bảng và trả về mọi bản ghi trong bảng. Điều này sẽ gây lãng phí tài nguyên I/O khi trả về các dòng không cần thiết.Do vậy, nên chú ý thêm vào mệnh đề WHERE trong câu lệnh SELECT để thu hẹp sốbộ trả về.
- Khi có sử dụng các dòng lệnh in-line hay block comments trong code thì chúng sẽ không ảnh hưởng tới việc xử lý hiệu năng trong một ứng dụng vì SQL Server bỏ qua các dòng này không biên dịch. Ngoài ra, những block comments còn làm rõ hơn các đoạn code của chương trình thuận lợi cho việc gỡ rối, nâng cấp.
- Khi sử dụng SQL Server Cursors thường chiếm dụng nhiều tài nguyên, giảm hiệu năng và tính mở của ứng dụng. Do vậy, nếu buộc phải thực hiện các thao tác theo hàng thì hãy tìm giải pháp khác như thực hiện tác vụ ở client là sử dụng các bảng trong tempdb; các bảng dẫn xuất; câu truy vấn có tương quan với nhau, hay sử dụng lệnh CASE. Thường thì tất cả kỹ thuật Non-cursor đều có thể sử dụng để thực hiện cùng các tác vụ như SQL Server cursor.
- Để xác định những câu truy vấn chậm có thể sử dụng vết ‘Time-SQL by Duration’ trong SQL Server Profiler để theo dõi thời gian xử lý của các câu truy vấn.
- Mệnh đề DISTINCT làm chậm quá trình truy vấn dữ liệu. Một số trường hợp đưa DISTINCT vào câu truy vấn ngay cả khi nó không cần thiết, cần cẩn thận cân nhắc xem có cần mệnh đề DISTINCT trong câu truy vấn hay không. - Khi dùng câu lệnh UNION, hãy để ý rằng ngầm định nó thực hiện tương đương như kết quả từ câu SELECT DISTINCT. Do đó nếu biết chắc rằng không có một dòng nào trùng lắp được tạo ra từ kết quả của UNION thì nên sử dụng câu lệnh UNION ALL thay thế.
- Câu lệnh SELECT *, sẽ trả về mọi cột trong bảng và ngoài ra nó còn cản trở việc sử dụng indexes. Trong câu truy vấn cần chú ý để không trả về các cột không cần thiết làm chậm tốc độ cũng như tăng lưu lượng I/O.
- Nếu người sử dụng thực hiện nhiều câu truy vấn đặc biệt trên SQL Server và các câu truy vấn được viết kém gây chiếm quá nhiều tài nguyên, ta nên cân nhắc sử dụng tuỳ chọn cấu hình ‘query governor cost limit’ để giới hạn thời gian câu truy vấn thực hiện. Ta có thể gán option này với giá trị là seconds và có 2 cách để xác định. Một là thay đổi nó ở cấp độ server bằng việc sử dụng sp_configure “query governor cost limit’” hoặc có thể gán nó ở cấp độ kết nối (chỉ có kết nối này có ảnh hưởng) bằng cách sử dụng lệnh SET QUERY_GOVERNOR_COST_LIMIT.
- Nếu trong ứng dụng cho phép người sử dụng chạy các câu truy vấn nhưng không thể ngăn cản được người sử dụng lấy về hàng trăm, thậm chí hàng ngàn bản ghi mà không cần thì hãy xem xét việc sử dụng toán tử TOP trong câu lệnh SELECT, chẳng hạn SELECT TOP 100 fullname, address FROM Customers. Ngoài việc sử dụng TOP, SQL Server còn hỗ trợ lệnh SET ROWCOUNT cũng nhằm hạn chế số records truy xuất từ câu SELECT nhưng lệnh SET ROWCOUNT này không hiệu quả bằng TOP.
- Hãy cố gắng tránh sử dụng các toán tử sau trong mệnh đề WHERE: "IS NULL", "<>", "!=", "!>", "!<", "NOT", "NOT EXISTS", "NOT IN", "NOT
LIKE", and "LIKE '%abc'". Vì những toán tử này không sử dụng đặc tính index mà thay vì thế máy tính sẽ dò tìm toàn bảng gây ảnh hưởng đến tốc độ của câu truy vấn. Ví dụ với câu lệnh:
SELECT lname, fname, address FROM Customers
WHERE fname LIKE ‘%V%’ thay vì thế, nên sử dụng:
SELECT lname, fname, address
FROM Customers WHERE fname LIKE ‘V%’
- Nếu có sự chọn lựa giữa IN và EXISTS trong câu truy vấn, hãy chọn EXISTS là tốt nhất. Tương tự như IN và BETWEEN, hãy chọn BETWEEN. - Nếu thấy rằng SQL Server sử dụng Table Scan thay vì INDEX SEEK trong câu truy vấn có IN hay OR, ngay cả cột tìm kiếm đó đã tạo index, nên sử dụng Index hint để bắt buộc trình tối ưu hoá truy vấn sử dụng index. Ví dụ trong câu lệnh như sau:
SELECT lname, fname, address FROM Customers
WHERE CusID in (1, 5, 10)
câu truy vấn sau sẽ chạy nhanh hơn câu trước vì ép sử dụng index: SELECT lname, fname, address
FROM Customers (INDEX = IX_CusID) WHERE CusID in (1, 5, 10)
- Tránh sử dụng Functions hoạt động trực tiếp vào cột vì index sẽ không được sử dụng. Ví dụ như trong câu lệnh:
FROM members
WHERE DATEDIFF(yy,datofbirth,GETDATE()) > 21 câu truy vấn sau sẽ sử dụng index:
SELECT member_number, first_name, last_name FROM members
WHERE dateofbirth < DATEADD(yy,-21,GETDATE())
- Không nên cài đặt các thuộc tính ràng buộc dữ liệu dư thừa trong cơ sở dữ liệu. Ví dụ nếu cài đặt các ràng buộc tham chiếu bằng khoá chính, khoá ngoài thì không nên thêm vào các triggers có cùng mục đích. Tương tự như vậy, đối với constraints và defaults hay constraints và rules.
- Nếu ứng dụng cần thêm giá trị nhị phân vào cột dữ liệu hình ảnh, hãy sử dụng Stored Procedure để thay thế cho câu lệnh INSERT được nhúng trong ứng dụng. Có lựa chọn lựa này vì đầu tiên ứng dụng phải chuyển giá trị nhị phân sang chuổi ký tự trưới khi nó gởi tới Server như vậy khi Server nhận được chuổi ký tự nó lại chuyển ngược lại dạng nhị phân.
- Nếu có thể, nên tránh sử dụng các hàm chuyển đổi kiểu dữ liệu trong mệnh đề WHERE.
- Nên đóng gói mã T_SQL trong một transaction nếu định sửa đổi cơ sở dữ liệu để bảo đảm tính nhất quán của dữ liệu. Còn đối với lệnh chỉ cho việc tạo reports thì không nên đóng gói thành một transaction vì khi mở và đóng một transaction sẽ tốn thêm chi phí.
- Không nên sử dụng các optimizer hint trong câu truy vấn vì thường thì rất khó đoán trước được Query Optimizer làm những gì. Optimizer hints là những từ khóa đặc biệt dùng để ép Query Optimizer chạy theo các từ khoá này.
- Trong các câu truy vấn có nhiều OR , có thể viết lại bằng cách kết hợp UNION ALL để tăng tốc độ truy vấn. Ví dụ:
SELECT employeeID, firstname, lastname FROM Employees
WHERE dept = 'prod' or city = 'Orlando' or division = 'food' câu truy vấn sau cùng mục đích nhưng có tốc độ nhanh hơn:
SELECT employeeID, firstname, lastname FROM Employees WHERE dept = 'prod'
UNION ALL
SELECT employeeID, firstname, lastname FROM Employees
WHERE city = 'Orlando' UNION ALL
SELECT employeeID, firstname, lastname FROM Employees
WHERE division = 'food'
- Trong khi Views rất thuận tiện trong việc hạn chế người sử dụng xem dữ liệu nhưng về vấn đề hiệu năng, sử dụng Views không tốt cho lắm. Vì Views không giống như SP, nó không được tối ưu hoá trước và ngay cùng câu lệnh SELECT bỏ trong View thì chạy chậm hơn câu lệnh đó chạy trong Query Analyzer. SQL Server không cấm việc sử dụng các Views lồng nhau nhưng nên tránh sử dụng các Views lồng nhau.
- Đừng sử dụng DISTINCT và ORDER BY trong câu lệnh SELECT trừ khi thật sự cần thiết đến chúng vì chúng làm tăng chi phí xử lý câu truy vấn. - Nếu câu SELECT có sử dụng HAVING thì nên có thêm việc sử dụng WHERE để hạn chế những hàng không cần thiết. Trình tự thực hiện câu truy vấn có cú pháp SELECT … WHERE … GROUP BY … HAVING …. Đầu tiên WHERE được sử dụng để chọn ra những dòng thích hợp mà cần phải
group. Kế đến GROUP BY chia các rows thành các tập records được nhóm và cuối cùng HAVING mới được sử dụng.
- Nếu ứng dụng sử dụng nhiều ký tự đại diện (wildcard) như % để tìm các chuổi dữ liệu, thì nên cân nhắc sử dụng tuỳ chọn SQL Server full-text. - Trong SQL Server 2000 cung cấp một kiểu dữ liệu mới gọi là ‘table’. Mục đích của nó là lưu trữ tạm thời tập các records. Nếu có thể, hãy sử dụng biến table thay vì sử dụng bảng tạm.
- Nếu cần xác định sự tồn tại của records trong bảng, đừng nên sử dụng SELECT COUNT(*) vì nó không hiệu quả và lãng phí tài nguyên thay vì thế nên sử dụng IF EXISTS thì hiệu quả hơn. Ví dụ:
IF (SELECT COUNT(*) FROM table_name
WHERE column_name = 'xxx') sử dụng IF EXISTS sẽ nhanh hơn:
IF EXISTS (SELECT * FROM table_name
WHERE column_name = 'xxx')
- Nếu được hãy sử dụng SP thay vì User defined Function trong một tập dữ liệu lớn mà ta muốn trả về. Bởi vì một User defined Function phức tạp thì chiếm nhiều chi phí hơn là một SP có cùng chức năng.
- Đôi khi muốn tìm phiên bản service pack mà ta đang chạy trên SQL Server, thì hãy sử dụng lệnh sau trong ISQL/W hay Query Analyzer:
SELECT @@Version
- Hãy sử dụng bảng dẫn xuất (derived table) để thay thế bảng tạm hay bảng chính. Ví dụ sau được copy từ Books Online:
FROM Northwind.dbo.Orders AS Ord INNER JOIN
(SELECTorderID,MAX(UnitPrice) AS maxUnitPrice FROM Northwind.dbo.[Order Details]
GROUP BY OrderID )
AS OrdDet ON ordDet.orderID = Ord.orderID
ORDER BY Ord.OrderID DESC, Ord.OrderDate, maxUnitPrice
3.1.2. Giới thiệu CSDL sinh viên của trường Cao đẳng kỹ thuật Viêng Chăn
Trường được thành lập năm 1986, Địa chỉ của trường nằm tại xã Nakhuea, huyện Viêng Khăm, tỉnh Viêng Chăn. Trường là nơi học tập chủ yếu của học sinh sinh viên nhân dân các dân tộc Lào. hạn chế nhưng qua 30 năm xây dựng và trưởng thành, tập thể nhà trường luôn đoàn kết, quyết tâm vượt khó vươn lên, khẳng định sự phát triển vững chắc và ngày càng đạt được những thành tích xuất sắc.
Tóm tắt cơ cấu tổ chức: Là trường có quy mô 17 lớp với 616 học sinh sinh viên, trong đó:
Bảng 3.1 Quy mô lớp học trường cao đẳng kỹ thuật Viêng Chăn
STT Khối Số lớp Số sinh viên Vị trí học Ghi chú
1 AC 11 373 Nhà A Tên lớp từ lớp AC1/1 đến lớp AC3/4 2 FN 6 243 Nhà A Tên lớp từ lớp FN1/1 đến lớp FN3/2 Tổng 17 616
Về CSDL trường cao đẳng kỹ thuật Viêng Chăn đưa vào ứng dụng như sau:
Quan hệ LOP (MaLop, TenLop, ViTriHoc), trong đó Lop là tên quan hệ lớp, MaLop là mã lớp, TenLop là tên lớp, ViTriHoc là vị trí học (Bảng 3.2).
Bảng 3.2 Quan hệ LOP:
MaLop TenLop ViTriHoc
AC1/1 Lớp AC1/1 Nhà A AC2/1 Lớp AC2/1 Nhà A AC3/4 Lớp AC3/1 Nhà A FN1/1 Lớp FN1/1 Nhà A FN3/2 Lớp FN3/2 Nhà A .... ... ...
Quan hệ HS-SV(MaSV, TenSV, GioiTinh, NgaySinh, QueQuan), trong đó HS-SV là tên quan hệ học sinh sinh viên, MaSV là mã sinh viên, TenSV là tên sinh viên, GioiTinh là giới tính, NgaySinh là ngày sinh, QueQuan là quê quán cho ở bảng 3.3.
Bảng 3.3 Quan hệ HS-SV:
MaSV TenHS GioiTinh NgaySinh QueQuan SV0001 Mino Thanasak Nam 16/01/1992 Attapue SV0016 Soudaxai Xaisouliyong Nam 28/07/1996 Bolikhamxai SV0383 Phetsamone Xaiyachak Nữ 30/07/1997 Luangphabang SV0454 Phetsamone Xaiyachak Nam 09/10/1997 Vientiane SV0600 ChindavonePhetluangsy Nữ 03/03/1998 Bokeo
... ... ... ... ...
Quan hệ KQHT (MaSV, MaLOP, TBCM, XepLoai), trong đó KQHT là tên quan hệ kết quả học tập, MaSV là mã sinh viên, MaLop là mã lớp, TBCM là trung bình các môn, XepLoai là xếp loại (bảng 3.4).
Bảng 3.4 Quan hệ KQHT:
MaHS MaLop TBCM XepLoai
SV0001 AC1/1 3,97 G SV0016 AC1/1 2,57 K SV0383 FN1/1 0,59 Kém SV0454 FN1/2 3,5 G SV0600 FN3/2 2,46 TB ... ... ... ...
Để minh hoạ những vấn đề lý thuyết về rút gọn câu truy vấn, luận văn đã sử dụng một số dữ liệu trong CSDL để thử nghiệm và đánh giá chất lượng việc tối ưu các câu lệnh truy vấn.
3.1.2. Một số dạng rút gọn câu vấn tin trên CSDL
3.1.2.1. Rút gọn cho phân mảnh ngang nguyên thuỷ.
Quan hệ LOP có thể được tách thành ba mảnh ngang như sau để chia thành khối lớp AC, FN:
LOPAC = MaLop “AC3/4” (LOP) LOPFN = MaLop > “AC3/4” (LOP)
Chương trình cục bộ hoá cho phân mảnh ngang trên là hợp các mảnh lại: LOP = LOPAC LOPFN
Vì vậy câu vấn tin gốc thực hiện trên LOP sẽ được thực hiện trên LOPAC LOPFN
Rút gọn với phép chọn
Câu hỏi 1: Hãy cho biết tên và vị trí của lớp có mã lớp là AC2/1
Theo yêu cầu cho biết tên lớp có mã là AC2/1 học ở đâu, khi đó ta tiến hành rút gọn cho phân mảnh ngang khi dùng câu vấn tin mẫu sau:
SELECT * FROM LOP
WHERE MaLop = “AC2/1” Kết quả chưa tối ưu như trong hình 3.1
Hình 3.1 Kết quả câu lệnh truy vấn ban đầu
Chương trình cục bộ hoá cho phân mảnh ngang LOP =LOPAC LOPFN
cho ra cây vấn tin gốc (hình 3.1a). Bằng cách hoán vị phép chọn với phép hợp (hình 3.2b), chúng ta dễ dàng phát hiện ra rằng vị từ chọn MaLop= “AC2/1” mâu thuẫn với vị từ phân mảnh LOPAC( MaLop “AC3/4”) và vị từ phân mảnh LOPAC (MaLop > “AC3/4”) do vậy tạo ra quan hệ rỗng. Câu truy vấn bấy giờ chỉ cần áp dụng trên LOPAC (hình 3.2c).
Kết quả truy vấn rút gọn (hình 3.3):
Hình 3.3 Kết quả rút gọn với phép chọn.
Hình 3.2 Rút gọn cho phân mảnh ngang (với phép chọn)
(c) Truy vấn rút gọn
MaLop = “AC2/1”
LOPAC
(a) Truy vấn gốc
MaLop = “AC2/1”
LOPAC LOPAC2/.. LOPFN
(b) Truy vấn đã đổi cho MaLop =“ AC2/1”
LOPAC LOPFN
* Rút gọn với phép nối
Giả sử LOP được phân mảnh thành LOPAC, LOPFN như sau: LOPAC = MaLop “AC3/4” (LOP); pLOPAC = (MaLop “AC3/4”)
LOPAC = “AC1/1” MaLop “AC3/4” (LOP); pLOPAC = (“AC1/1” MaLop
“AC3/4”)
LOPFN = MaLop > “AC3/4” (LOP); pLOPAC = (MaLop > “AC3/4”) và quan hệ KQHT được phân mảnh ngang như sau:
KQHT1 = MaLop “AC3/4” (KQHT); pKQHT1 = (MaLop “AC3/4”) KQHT2 = MaLop “AC3/4” (KQHT); pKQHT2 = (MaLop >“AC3/4”)
Như vậy LOPFN và KQHT2 được định nghĩa bởi cùng một vị từ. Ngoài ra vị từ định nghĩa KQHT1 là hợp của các vị từ định nghĩa mảnh LOPAC.
Câu hỏi 2: Hãy cho biết thông tin chung và kết quả học tập của sinh viên
Ta xét câu truy vấn nối sau: SELECT *
FROM LOP, KQHT
WHERE LOP.MaLop = KQHT.MaLop
Câu truy vấn gốc tương đương được trình bày trong hình 3.4.
Câu truy vấn rút gọn bằng cách phân phối các nối trên hợp và việc áp dụng qui tắc 2, kết quả rút gọn ở hình 3.5.
LOPAC LOPFN KQHTH1 KQHTH2
Hình 3.4 Truy vấn gốc
pLOPAC pKQHT1 = (MaLop “AC1/4”) (MaLop “AC3/4”)= True
pLOPAC pKQHT1 = (“AC1/4” MaLop “AC3/4”) (MaLop “AC3/4”) = True
pLOPFN pKQHTH1=(MaLop >“AC3/4”)(MaLop “AC3/4”) = False
cho quan hệ rỗng
pLOPAC pKQHT2 = (MaLop “AC1/4”) (MaLop >“AC3/4”) = False
cho quan hệ rỗng
pLOPAC pKQHT2 = (“AC1/1” MaLop “AC3/4”) (MaLop >“AC3/4”)= False
cho quan hệ rỗng
pLOPFN pKQHTH2=(MaLop >“AC3/4”)(MaLop >“AC3/4”)= True
Kết quả truy vấn đã rút gọn với phép nối (hình 3.6):
3.1.2.2 Rút gọn cho phân mảnh dọc LOPAC KQHT1 LOPFN KQHTH2 Hình 3.5 Truy vấn đã rút gọn MaLop MaLop
Quan hệ LOP có thể được phân thành hai mảnh dọc, trong đó thuộc tính khóa MaLop phải có mặt trong mọi mảnh dọc.
LOPV1 = MaLop , TenLop (LOP) LOPV2 = MaLop, ViTriHoc (LOP) Chương trình cục bộ hóa là LOP = LOPV1 LOPV2
Câu hỏi 3: Hãy cho biết câu truy vấn SQL trong quan hệ lớp cho phân