Tìm kiếm hiệu quả không phân biệt dạng chữ với pureXML DB2
Tìm kiếm và sắp xếp dữ liệu XML theo cách không phân biệt dạng chữ
Matthias Nicola, Chuyên gia về hiệu năng CSDL, IBM Silicon Valley Laboratory
Tóm tắt: Các giá trị của các phần tử và các thuộc tính XML, theo định nghĩa, là
phân biệt dạng chữ. Ví dụ, nếu bạn tìm kiếm các phần tử <city> cho giá trị "Paris",
bạn sẽ không tìm thấy "PARIS" hoặc "paris". Điều này có thể được giải quyết
bằng các hàm XQuery như fn:upper-case(), nhưng hiệu năng sẽ không phải luôn
luôn tối ưu do việc sử dụng các hàm như vậy cản trở việc sử dụng các chỉ số
XML. Bài viết này giải thích cách tạo ra một cơ sở dữ liệu không phân biệt dạng
chữ khi sử dụng DB2® pureXML™ và hành vi hay xảy ra trong truy vấn XML và
các chỉ mục XML
Mục lục
Case-insensitive search with upper/lower case functions
Creating a case-insensitive database in DB2
Query XML data in a case-insensitive database
Performance
Summary
Tìm kiếm không phân biệt dạng chữ với các hàm chữ hoa và chữ thường
Ví dụ sau sẽ cho bạn một sự hiểu biết rõ ràng hơn về tìm kiếm không phân biệt
dạng chữ. Liệt kê 1 định nghĩa một bảng có một cột số nguyên (INTEGER) và một
cột XML và chèn 7 hàng vào trong bảng đó. Mỗi hàng có chứa một tài liệu khách
hàng nhỏ có chứa một phần tử XML <city>.
Các giá trị trong phần tử này khác nhau về chữ hoa và chữ thường. Một số giá trị
tất cả là chữ hoa, một số giá trị tất cả là chữ thường và một số trường hợp trộn lẫn
("ký tự chữ hoa đầu tiên"). Điều này có thể xảy ra khi dữ liệu này đã đến từ một
loạt các ứng dụng có sử dụng các quy tắc khác nhau để nhập vào dữ liệu chữ hoa
và chữ thường.
Liệt kê 1. Bảng và dữ liệu mẫu
CREATE TABLE customer (id INTEGER, xmldoc XML);
INSERT INTO customer (id, xmldoc) VALUES
(1,'<Customer id="1"><city>PARIS</city></Customer>'),
(2,'<Customer id="2"><city>Tokyo</city></Customer>'),
(3,'<Customer id="3"><city>tokyo</city></Customer>'),
(4,'<Customer id="4"><city>PARIS</city></Customer>'),
(5,'<Customer id="5"><city>paris</city></Customer>'),
(6,'<Customer id="6"><city>Delhi</city></Customer>'),
(7,'<Customer id="7"><city>Paris</city></Customer>');
Một ứng dụng truy vấn các tài liệu XML này để tìm kiếm các khách hàng với một
thành phố cụ thể hầu như đòi hỏi tìm kiếm không phân biệt dạng chữ. Ví dụ, bạn
có thể muốn tìm tất cả các khách hàng ở Paris và hy vọng sẽ lấy ra hàng 1, 4, 5 và
7. Tuy nhiên, nếu bạn tìm kiếm giá trị "Paris", thì chỉ có hàng 7 được trả về. Để
tóm lấy tất cả bốn hàng mà bạn cần, bạn có thể sử dụng hàm XQuery fn:upper-
case() để biến đổi các giá trị phần tử thành phố thành dạng chữ hoa và so sánh
chúng với ""PARIS". Điều này được chỉ ra trong truy vấn trong Liệt kê 2 nó trả về
tất cả bốn khách hàng ở Paris.
Liệt kê 2. Chọn các khách hàng ở Paris
SELECT id, XMLCAST( XMLQUERY('$XMLDOC/Customer/city') AS
VARCHAR(15)) AS city
FROM customer
WHERE XMLEXISTS('$XMLDOC/Customer[fn:upper-case(city) =
"PARIS"]');
Nếu truy vấn của bạn sử dụng một dấu tham số cho giá trị tìm kiếm, rồi tham số
này cũng sẽ được biến đổi sang dạng chữ hoa. Điều này được thể hiện trong Liệt
kê 3. Dấu tham số ("?") được gõ vào là VARCHAR(15) và được chuyển vào vị từ
XQuery như là biến "c".
Liệt kê 3. Chọn các khách hàng khi sử dụng một dấu tham số
SELECT id, XMLCAST( XMLQUERY('$XMLDOC/Customer/city') AS
VARCHAR(15)) AS city
FROM customer
WHERE XMLEXISTS('$XMLDOC/Customer[fn:upper-case(city) = fn:upper-
case($c)]'
PASSING CAST(? AS VARCHAR(15)) AS "c");
Hình 1 cho thấy kết quả đầu ra của các truy vấn thí dụ ở trên.
Hình 1. Kết quả của truy vấn thí dụ
Tất cả điều này thực hiện tốt nếu bạn đang truy vấn chỉ một số lượng nhỏ dữ liệu
hoặc nếu các truy vấn của bạn cũng chứa các vị từ chọn như là vị từ dạng chữ hoa
được áp dụng chỉ cho một tập kết quả trung gian nhỏ. Vấn đề là vị từ có hàm
fn:upper-case() ngăn cản sử dụng các chỉ mục XML trong DB2. Do đó, cách tiếp
cận này không thích hợp với số lượng lớn dữ liệu.
Để tránh việc sử dụng hàm fn:upper-case() và lợi dụng các lợi ích của các chỉ mục
XML, cần thiết tạo ra một cơ sở dữ liệu không phân biệt dạng chữ.
Tạo một cơ sở dữ liệu không phân biệt dạng chữ trong DB2
DB2 hỗ trợ phép đối chiếu Unicode nhận biết-cục bộ kể từ Phiên bản 9.5 Bản sửa
lỗi 1. Điều này cho phép bạn bỏ qua dạng chữ và/hoặc các dấu. Để tạo một cơ sở
dữ liệu không phân biệt dạng chữ cho tất cả các phép so sánh chuỗi, cần thiết sử
dụng đối chiếu UCA500R1 như trong Liệt kê 4.
Liệt kê 4. Tạo một cơ sở dữ liệu không phân biệt dạng chữ
CREATE DATABASE testdb
USING CODESET UTF-8 TERRITORY US
COLLATE USING UCA500R1_LEN_S2;
Điều chuỗi UCA500R1_LEN_S2 có nghĩa chính xác gì? UCA500R1 UCA500R1
xác định rằng Unicode Collation Algorithm (UCA –Thuật toán phép đối chiếu
Unicode) mặc định dựa trên phiên bản 5.0.0 chuẩn Unicode được sử dụng trong cơ
sở dữ liệu này. Do UCA mặc định không thể kiểm soát đối chiếu chuỗi của mỗi
ngôn ngữ được Unicode hỗ trợ cùng một lúc, việc bố trí các ký tự có thể được tùy
chỉnh bằng cách sử dụng các thuộc tính tùy chọn. Các thuộc tính này được phân
tách bằng một dấu gạch dưới (_). Từ khóa UCA500R1 cùng với các thuộc tính bất
kỳ tạo nên một tên đối chiếu UCA.
Tên đối chiếu được sử dụng trong Liệt kê 4 chứa hai thuộc tính: LEN và S2. LEN
là của L (ngôn ngữ) và EN (mã ngôn ngữ ISO 639-1 cho tiếng Anh). Thuộc tính
thứ hai S2 xác định mức độ mạnh mà nó quyết định có tính đến hay không dạng
chữ hay trọng âm khi sắp xếp hoặc so sánh các chuỗi. Trong Liệt kê 4 mức độ
mạnh 2 được sử dụng để cho "PARIS" và "paris" là như nhau. Sau đây là các ví dụ
về các giá trị khác có thể có:
UCA500R1_LEN_S1 sẽ đối chiếu "cliche" = "Cliche" = "cliché"
UCA500R1_LEN_S2 sẽ đối chiếu "cliche" = "Cliche" < "cliché"
UCA500R1_LEN_S3 sẽ đối chiếu "cliche" < "Cliche" < "cliché"
Có thể tìm thấy trong Trung tâm Thông tin DB2 (xem Tài nguyên) một danh sách
tất cả các cách kết hợp có khả năng để sử dụng như một tên đối chiếu UCA.
Truy vấn dữ liệu XML trong cơ sở dữ liệu không phân biệt dạng chữ
Do cơ sở dữ liệu đã được tạo ra bằng cách sử dụng tên đối chiếu UCA500R1 với
mức độ mạnh 2, các truy vấn trước đó bây giờ có thể được viết đơn giản như khi
tất cả các dữ liệu thực sự sẽ là chữ hoa, mà không dùng hàm fn:upper-case() (Liệt
kê 5). Nó thậm chí không quan trọng cho dù chuỗi tìm kiếm là "Paris" hoặc
"PARIS" hoặc sự kết hợp nào khác của chữ hoa hay chữ thường.
Liệt kê 5. Chọn các khách hàng ở Paris
SELECT id, XMLCAST( XMLQUERY('$XMLDOC/Customer/city') AS
VARCHAR(15)) AS city
FROM customer
WHERE XMLEXISTS('$XMLDOC/Customer[city = "PARIS"]');
Hình 2. Kết quả truy vấn thí dụ
Nếu bạn thêm một mệnh đề ORDER BY để sắp xếp theo giá trị thành phố được
trích ra, tập kết quả vẫn duy trì như nhau: PARIS, paris và Paris được coi như là
cùng giá trị.
Để truy vấn dữ liệu này một cách hiệu quả, đặc biệt là nếu số hàng trong bảng lớn,
bạn nên tạo một chỉ mục XML trên XPath là /Customer/city, như Liệt kê 6 cho
thấy:
Liệt kê 6. Tạo một chỉ mục XML
CREATE INDEX customer_lang_idx ON test (xmldoc) GENERATE KEY
USING XMLPATTERN
'/Customer/city' AS SQL VARCHAR(15);
giải thích truy vấn (bằng Visual Explain hoặc db2exfmt), bạn thấy rằng chỉ số
được sử dụng để tìm kiếm không phân biệt dạng chữ:
Hình 3. Kế hoạch giải thích để truy vấn tất cả các khách hàng ở Paris trong
một cơ sở dữ liệu không phân biệt dạng chữ
Mặt hạn chế tiềm ẩn của cách tiếp cận đã mô tả trong phần này là tất cả các dữ liệu
trong tất cả các cột trong tất cả các bảng trong toàn thể cơ sở dữ liệu được xử lý
theo cách không phân biệt dạng chữ. Không thể hạn chế không phân biệt dạng chữ
cho các bảng hay các cột cụ thể. Đó là tất cả hoặc không.
Lưu ý rằng không phân biệt dạng chữ chỉ áp dụng cho các giá trị phần tử và thuộc
tính, chứ không phải tên thẻ của chúng. Các thẻ và biểu thức đường dẫn XML vẫn
còn phân biệt dạng chữ. Ví dụ, hai biểu thức XPath là /Customer/city (chữ "c" viết
thường) và /Customer/City (chữ "C" viết hoa) là khác nhau. Cái sau sẽ không tìm
thấy bất kỳ phần tử nào trong dữ liệu mẫu của chúng tôi bởi vì các phần tử <city>
trong dữ liệu mẫu của chúng tôi được viết theo chữ thường.
Hiệu năng
Sử dụng một phép đối chiếu tùy chỉnh cho cơ sở dữ liệu có thể tác động đến hiệu
năng truy vấn do số lượng của lần khớp các chuỗi có thể sẽ tăng lên khi bạn chọn
một giá trị thiết lập UCA lỏng hơn. Nói cách khác, các phép so sánh chuỗi có thể
tốn kém hơn trong cơ sở dữ liệu không phân biệt dạng chữ. Để kiểm tra sự khác
biệt hiệu năng giữa các truy vấn các cơ sở dữ liệu phân biệt dạng chữ và không
phân biệt dạng chữ, chúng tôi đã tạo ra một cơ sở dữ liệu thông thường (phân biệt
dạng chữ) và một cơ sở dữ liệu không phân biệt dạng chữ. Chúng tôi đưa vào
20.000 tài liệu CustAcc từ khung chuẩn TPoX và đo một loạt các truy vấn trong cả
hai cơ sở dữ liệu.
Đối với các truy vấn chỉ có một số hàng nhỏ đến trung bình, sự khác biệt hiệu
năng giữa hai cơ sở dữ liệu kiểm tra không đáng kể. Chúng tôi đã thấy một sự
khác biệt lớn hơn đối với các truy vấn có một số lượng lớn các hàng, chẳng hạn
như một hoạt động quét bảng qua tất cả 20.000 tài liệu XML so với phép so sánh
chuỗi trên mỗi tài liệu. Các truy vấn như vậy đã lâu hơn 5% đến 8% trong cơ sở
dữ liệu không phân biệt dạng chữ. Một chi phí nhỏ phải trả cho tìm kiếm phân biệt
dạng chữ.
Tóm tắt
Có một số phương pháp để tìm kiếm dữ liệu DB2 theo cách không phân biệt dạng
chữ như việc sử dụng các cột đã tạo ra (xem Tài nguyên). Trong khi các phương
pháp này có thể làm việc tốt với dữ liệu quan hệ, nhưng chúng không phù hợp với
truy vấn dữ liệu XML. Việc tạo ra một cơ sở dữ liệu với đối chiếu Unicode tùy
chỉnh là cách tốt nhất để đạt được xử lý dữ liệu XML không phân biệt dạng chữ.
Điều này làm cho mọi sự so sánh giá trị chuỗi trong cơ sở dữ liệu là không phân
biệt dạng chữ và cho phép sử dụng các chỉ mục XML và các chỉ số quan hệ như
bình thường. Chi phí hoạt động của việc tăng các mẫu tìm kiếm (liên quan đến
dạng chữ hoặc dấu) đã chứng tỏ là rất thấp.