Database
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Database

Các cột ảo và chỉ mục chức năng

Thường xuyên, chúng ta thấy các truy vấn SQL phức tạp được viết kém chạy trên các bảng cơ sở dữ liệu. Các truy vấn như vậy có thể mất một thời gian rất ngắn hoặc rất lâu để thực thi, nhưng chúng tiêu tốn một lượng lớn CPU và các tài nguyên khác. Tuy nhiên, trong nhiều trường hợp, các truy vấn phức tạp cung cấp thông tin có giá trị cho người / ứng dụng. Do đó, nó mang lại các tài sản hữu ích trong tất cả các loại ứng dụng.

Độ phức tạp của truy vấn

Hãy xem xét kỹ hơn các truy vấn có vấn đề. Nhiều người trong số họ rất phức tạp. Điều đó có thể do một số lý do:

  1. Kiểu dữ liệu được chọn cho dữ liệu;
  2. Tổ chức và lưu trữ dữ liệu trong cơ sở dữ liệu;
  3. Chuyển đổi và kết hợp dữ liệu trong một truy vấn để truy xuất tập kết quả mong muốn.

Bạn cần phải nghĩ ra ba yếu tố chính này đúng cách và triển khai chúng một cách chính xác để làm cho các truy vấn hoạt động tối ưu.

Tuy nhiên, nó có thể trở thành một nhiệm vụ gần như bất khả thi đối với cả Nhà phát triển cơ sở dữ liệu và DBA. Ví dụ, có thể đặc biệt khó khăn khi thêm chức năng mới vào các hệ thống Kế thừa hiện có. Một trường hợp đặc biệt phức tạp là khi bạn cần trích xuất và chuyển đổi dữ liệu từ một hệ thống cũ để bạn có thể so sánh nó với dữ liệu được tạo ra bởi hệ thống hoặc chức năng mới. Bạn phải đạt được nó mà không ảnh hưởng đến chức năng ứng dụng kế thừa.

Các truy vấn như vậy có thể liên quan đến các phép nối phức tạp, như sau:

  1. Sự kết hợp của chuỗi con và / hoặc nối nhiều cột dữ liệu;
  2. Các hàm vô hướng được tích hợp sẵn;
  3. UDF được tùy chỉnh;
  4. Bất kỳ sự kết hợp nào giữa các so sánh mệnh đề WHERE và các điều kiện tìm kiếm.

Các truy vấn, như đã mô tả trước đó, thường có các đường dẫn truy cập phức tạp. Tệ hơn nữa, chúng có thể có nhiều lần quét bảng và / hoặc quét toàn bộ chỉ mục với sự kết hợp của các phép tìm kiếm hoặc các phép tìm kiếm như vậy đang diễn ra.

Thao tác và chuyển đổi dữ liệu trong truy vấn

Chúng tôi cần chỉ ra rằng tất cả dữ liệu được lưu trữ liên tục trong bảng cơ sở dữ liệu cần phải chuyển đổi và / hoặc thao tác tại một số điểm khi chúng tôi truy vấn dữ liệu đó từ bảng. Sự biến đổi có thể bao gồm từ một phép biến đổi đơn giản đến một phép biến đổi rất phức tạp. Tùy thuộc vào mức độ phức tạp của nó, quá trình chuyển đổi có thể tiêu tốn nhiều CPU và tài nguyên.

Trong hầu hết các trường hợp, các phép biến đổi được thực hiện trong JOIN xảy ra sau khi dữ liệu được đọc và giảm tải xuống tempdb cơ sở dữ liệu (SQL Server) hoặc workfile cơ sở dữ liệu / không gian bảng tạm thời như trong các hệ thống cơ sở dữ liệu khác.

Vì dữ liệu trong workfile không thể lập chỉ mục , thời gian cần thiết để thực hiện các phép biến đổi kết hợp và các phép tham gia sẽ tăng lên theo cấp số nhân. Dữ liệu được truy xuất trở nên lớn hơn. Do đó, các truy vấn kết quả phát triển thành một nút cổ chai về hiệu suất thông qua tăng trưởng dữ liệu bổ sung.

Vì vậy, làm cách nào một Nhà phát triển cơ sở dữ liệu hoặc một DBA có thể giải quyết các tắc nghẽn hiệu suất đó một cách nhanh chóng và đồng thời cung cấp cho họ nhiều thời gian hơn để thiết kế lại và viết lại các truy vấn để có hiệu suất tối ưu?

Có hai cách để giải quyết những vấn đề dai dẳng như vậy một cách hiệu quả. Một trong số đó là sử dụng các cột ảo và / hoặc chỉ mục chức năng.

Chỉ mục chức năng và truy vấn

Thông thường, bạn tạo chỉ mục trên các cột chỉ ra một tập hợp cột / giá trị duy nhất trong một hàng (chỉ mục duy nhất hoặc khóa chính) hoặc đại diện cho một tập hợp các cột / giá trị được hoặc có thể được sử dụng trong điều kiện tìm kiếm mệnh đề WHERE của truy vấn.

Nếu bạn không có các chỉ mục như vậy và bạn đã phát triển các truy vấn phức tạp như đã mô tả trước đó, bạn sẽ nhận thấy những điều sau:

  1. Giảm mức hiệu suất khi sử dụng giải thích truy vấn và xem các bản quét bảng hoặc quét toàn bộ chỉ mục
  2. Sử dụng tài nguyên và CPU rất cao do các truy vấn gây ra;
  3. Thời gian thực hiện lâu.

Cơ sở dữ liệu hiện đại thường giải quyết những vấn đề này bằng cách cho phép bạn tạo chức năng hoặc dựa trên chức năng chỉ mục, như được đặt tên trong SQLServer, Oracle và MySQL (v 8.x). Hoặc, nó có thể là Lập chỉ mục trên biểu thức / dựa trên biểu thức chỉ mục, như trong các cơ sở dữ liệu khác (PostgreSQL và Db2).

Giả sử bạn có cột Ngày mua hàng thuộc loại dữ liệu TIMESTAMP hoặc DATETIME trong Đơn đặt hàng của bạn bảng và cột đó đã được lập chỉ mục. Chúng tôi bắt đầu truy vấn Đơn đặt hàng bảng có mệnh đề WHERE:

SELECT ...
FROM Order
WHERE DATE(Purchase_Date) = '03.12.2020'

Giao dịch này sẽ thực hiện quét toàn bộ chỉ mục. Tuy nhiên, nếu cột chưa được lập chỉ mục, bạn sẽ quét bảng.

Sau khi quét toàn bộ chỉ mục, chỉ mục đó sẽ chuyển vào tempdb / workfile ( toàn bộ bảng nếu bạn nhận được bảng quét ) trước khi khớp với giá trị 03.12.2020 .

Vì một bảng Đơn đặt hàng lớn sử dụng nhiều CPU và tài nguyên, bạn nên tạo chỉ mục chức năng có biểu thức DATE ( Ngày mua hàng ) dưới dạng một trong các cột chỉ mục và được hiển thị bên dưới:

CREATE ix_DatePurchased on sales.Order(Date(Purchase_Date) desc, ... )

Khi làm như vậy, bạn tạo vị từ phù hợp DATE (Purchase_Date) =‘03 .12.2020 ’ có thể lập chỉ mục. Do đó, thay vì di chuyển chỉ mục hoặc bảng đến tempdb / workfile trước khi khớp giá trị, chúng tôi làm cho chỉ mục chỉ được truy cập và / hoặc quét một phần. Điều này dẫn đến việc sử dụng tài nguyên và CPU thấp hơn.

Hãy xem một ví dụ khác. Có một Khách hàng bảng có các cột first_name, last_name . Các cột đó được lập chỉ mục như sau:

CREATE INDEX ix_custname on Customer(first_name asc, last_name asc),

Bên cạnh đó, bạn có chế độ xem nối các cột này thành tên_khách_hàng cột:

CREATE view v_CustomerInfo( customer_name, .... ) as
select first_name ||' '|| last_name as customer_name,.....
from Customer
where ...

Bạn có một truy vấn từ hệ thống Thương mại điện tử tìm kiếm tên đầy đủ của khách hàng:

select c.*
from v_CustomerInfo c
where c.customer_name = 'John Smith'
....

Một lần nữa, truy vấn này sẽ tạo ra một bản quét chỉ mục đầy đủ. Trong trường hợp xấu nhất, đây sẽ là một quá trình quét toàn bộ bảng di chuyển tất cả dữ liệu từ chỉ mục hoặc bảng sang tệp làm việc trước khi nối first_name last_name và khớp với giá trị "John Smith".

Một trường hợp khác là tạo chỉ mục chức năng như hình dưới đây:

CREATE ix_fullcustname on sales.Customer( first_name ||' '|| last_name desc, ... )

Bằng cách này, bạn có thể thực hiện nối trong truy vấn dạng xem thành một vị từ có thể lập chỉ mục. Thay vì quét toàn bộ chỉ mục hoặc quét bảng, bạn có quét chỉ mục một phần. Việc thực thi truy vấn như vậy dẫn đến việc sử dụng tài nguyên và CPU thấp hơn, loại trừ công việc trong workfile và do đó đảm bảo thời gian thực thi nhanh hơn.

Cột và truy vấn ảo (được tạo)

Các cột đã tạo (cột ảo hoặc cột được tính toán) là các cột chứa dữ liệu được tạo nhanh chóng. Dữ liệu không thể được đặt một cách rõ ràng thành một giá trị cụ thể. Nó đề cập đến dữ liệu trong các cột khác được truy vấn, chèn hoặc cập nhật trong một truy vấn DML.

Việc tạo giá trị của các cột như vậy được tự động hóa dựa trên một biểu thức. Những biểu thức này có thể tạo ra:

  1. Một chuỗi các giá trị nguyên;
  2. Giá trị dựa trên giá trị của các cột khác trong bảng;
  3. Nó có thể tạo ra các giá trị bằng cách gọi các hàm tích hợp sẵn hoặc các hàm do người dùng xác định (UDF).

Điều quan trọng không kém cần lưu ý là trong một số cơ sở dữ liệu (SQLServer, Oracle, PostgreSQL, MySQL và MariaDB), các cột này có thể được cấu hình để lưu trữ dữ liệu liên tục với việc thực thi câu lệnh INSERT và UPDATE hoặc thực thi biểu thức cột bên dưới một cách nhanh chóng nếu chúng tôi truy vấn bảng và cột tiết kiệm dung lượng lưu trữ.

Tuy nhiên, khi biểu thức phức tạp, cũng như với logic phức tạp trong hàm UDF, việc tiết kiệm thời gian thực thi, tài nguyên và chi phí truy vấn CPU có thể không nhiều như mong đợi.

Do đó, chúng ta có thể cấu hình cột để nó liên tục lưu trữ kết quả của biểu thức trong một câu lệnh INSERT hoặc UPDATE. Sau đó, chúng tôi tạo một chỉ mục thông thường trên cột đó. Bằng cách này, chúng tôi sẽ tiết kiệm CPU, mức sử dụng tài nguyên và thời gian thực hiện truy vấn. Một lần nữa, nó có thể tăng nhẹ hiệu suất INSERT và UPDATE, tùy thuộc vào độ phức tạp của biểu thức.

Hãy xem một ví dụ. Chúng ta khai báo bảng và tạo chỉ mục như sau:

CREATE TABLE Customer as (
  customerID Int GENERATED ALWAYS AS IDENTITY,
  first_name VARCHAR(50) NOT NULL,
  last_name VARCHAR(50) NOT NULL,
  customer_name as (first_name ||' '|| last_name) PERSISTED
  ...
  );
CREATE ix_fullcustname on sales.Customer( customer_name desc, ... )

Bằng cách này, chúng ta di chuyển logic nối từ dạng xem trong ví dụ trước xuống bảng và lưu trữ dữ liệu một cách bền bỉ. Chúng tôi truy xuất dữ liệu bằng cách quét đối sánh trên một chỉ mục thông thường. Đó là kết quả tốt nhất có thể ở đây.

Bằng cách thêm cột đã tạo vào bảng và tạo chỉ mục thông thường trên cột đó, chúng ta có thể di chuyển logic chuyển đổi xuống cấp bảng. Ở đây, chúng tôi liên tục lưu trữ dữ liệu đã chuyển đổi trong các câu lệnh chèn hoặc cập nhật mà nếu không sẽ được chuyển đổi trong các truy vấn. Quá trình quét JOIN và INDEX sẽ đơn giản và nhanh hơn nhiều.

Chỉ mục chức năng, cột được tạo và JSON

Các ứng dụng di động và web toàn cầu sử dụng cấu trúc dữ liệu nhẹ như JSON để di chuyển dữ liệu từ web / thiết bị di động sang cơ sở dữ liệu và ngược lại. Dấu chân nhỏ của cấu trúc dữ liệu JSON làm cho việc truyền dữ liệu qua mạng nhanh chóng và dễ dàng. Có thể dễ dàng nén JSON ở kích thước rất nhỏ so với các cấu trúc khác, tức là XML. Nó có thể làm tốt hơn các cấu trúc trong phân tích cú pháp thời gian chạy.

Do việc sử dụng ngày càng nhiều cấu trúc dữ liệu JSON, cơ sở dữ liệu quan hệ có định dạng lưu trữ JSON là kiểu dữ liệu BLOB hoặc kiểu dữ liệu CLOB. Cả hai loại này đều làm cho dữ liệu trong các cột như vậy không thể lập được.

Vì lý do này, các nhà cung cấp cơ sở dữ liệu đã giới thiệu các hàm JSON để truy vấn và sửa đổi các đối tượng JSON, vì bạn có thể dễ dàng tích hợp các hàm này vào truy vấn SQL hoặc các lệnh DML khác. Tuy nhiên, các truy vấn này phụ thuộc vào độ phức tạp của đối tượng JSON. Chúng rất tốn CPU và tài nguyên, vì các đối tượng BLOB và CLOB cần được giảm tải vào bộ nhớ hoặc tệ hơn là vào workfile trước khi truy vấn và / hoặc thao tác.

Giả sử rằng chúng ta có Khách hàng bảng với Chi tiết khách hàng dữ liệu được lưu trữ dưới dạng đối tượng JSON trong cột có tên CustomerDetail . Chúng tôi thiết lập truy vấn bảng như sau:

SELECT CustomerID,
  JSON_VALUE(CustomerDetail, '$.customer.Name') AS Name,
  JSON_VALUE(CustomerDetail, '$.customer.Surname') AS Surname,
  JSON_VALUE(CustomerDetail, '$.customer.address.PostCode') AS PostCode,
  JSON_VALUE(CustomerDetail, '$.customer.address."Address Line 1"') + ' '
  + JSON_VALUE(CustomerDetail, '$.customer.address."Address Line 2"') AS Address,
  JSON_QUERY(CustomerDetail, '$.customer.address.Country') AS Country
FROM Customer
WHERE ISJSON(CustomerDetail) > 0
  AND JSON_VALUE(CustomerDetail, '$.customer.address.Country') = 'Iceland'
  AND JSON_VALUE(CustomerDetail, '$.customer.address.PostCode') IN (101,102,110,210,220)
  AND Status = 'Active'
ORDER BY JSON_VALUE(CustomerDetail, '$.customer.address.PostCode')

Trong ví dụ này, chúng tôi đang truy vấn dữ liệu cho khách hàng sống ở một số vùng của Vùng thủ đô ở Iceland. Tất cả Đang hoạt động dữ liệu phải được truy xuất vào workfile trước khi áp dụng vị từ tìm kiếm. Tuy nhiên, việc truy xuất sẽ dẫn đến việc sử dụng tài nguyên và CPU quá lớn.

Theo đó, có một thủ tục hiệu quả để làm cho các truy vấn JSON chạy nhanh hơn. Nó liên quan đến việc sử dụng chức năng thông qua các cột đã tạo, như đã mô tả trước đây.

Chúng tôi đạt được hiệu suất tăng bằng cách thêm các cột đã tạo. Một cột được tạo sẽ tìm kiếm trong tài liệu JSON để tìm dữ liệu cụ thể được trình bày trong cột bằng cách sử dụng các hàm JSON và lưu trữ giá trị vào cột.

Chúng tôi có thể lập chỉ mục và truy vấn các cột được tạo này bằng cách sử dụng SQL thông thường điều kiện tìm kiếm mệnh đề where. Do đó, việc tìm kiếm dữ liệu cụ thể trong các đối tượng JSON trở nên rất nhanh.

Chúng tôi thêm hai cột đã tạo - Quốc gia Mã bưu điện :

ALTER TABLE Customer
ADD Country as JSON_VALUE(CustomerDetail,'$.customer.address.Country');
ALTER TABLE Customer
ADD PostCode as JSON_VALUE(CustomerDetail,'$.customer.address.PostCode');

CREATE INDEX ix_CountryPostCode on Country(Country asc,PostCode asc);

Ngoài ra, chúng tôi tạo một chỉ mục tổng hợp trên các cột cụ thể. Bây giờ, chúng ta có thể thay đổi truy vấn thành ví dụ được hiển thị bên dưới:

SELECT CustomerID,
  JSON_VALUE(CustomerDetail, '$.customer.customer.Name') AS Name,
  JSON_VALUE(CustomerDetail, '$.customer.customer.Surname') AS Surname,
  JSON_VALUE(CustomerDetail, '$.customer.address.PostCode') AS PostCode,
  JSON_VALUE(CustomerDetail, '$.customer.address."Address Line 1"') + ' '
  + JSON_VALUE(CustomerDetail, '$.customer.address."Address Line 2"') AS Address,
  JSON_QUERY(CustomerDetail, '$.customer.address.Country') AS Country
FROM Customer
WHERE ISJSON(CustomerDetail) > 0
  AND Country = 'Iceland'
  AND PostCode IN (101,102,110,210,220)
  AND Status = 'Active'
ORDER BY JSON_VALUE(CustomerDetail, '$.customer.address.PostCode')

Điều này giới hạn việc truy xuất dữ liệu chỉ dành cho Khách hàng đang hoạt động ở một số khu vực của Vùng thủ đô Iceland. Cách này nhanh hơn và hiệu quả hơn so với truy vấn trước đó.

Kết luận

Nói chung, bằng cách áp dụng các cột ảo hoặc chỉ mục chức năng cho các bảng gây khó khăn (CPU và các truy vấn nặng về tài nguyên), chúng tôi có thể loại bỏ các vấn đề khá nhanh chóng.

Các cột ảo và chỉ mục chức năng có thể giúp truy vấn các đối tượng JSON phức tạp được lưu trữ trong các bảng quan hệ thông thường. Tuy nhiên, chúng tôi cần đánh giá kỹ các vấn đề trước và thực hiện các thay đổi cần thiết cho phù hợp.

Trong một số trường hợp, nếu cấu trúc dữ liệu truy vấn và / hoặc JSON rất phức tạp, một phần của việc sử dụng tài nguyên và CPU có thể chuyển từ truy vấn sang quy trình CHÈN / CẬP NHẬT. Nó cung cấp cho chúng tôi ít CPU tổng thể và tiết kiệm tài nguyên hơn so với dự kiến. Nếu bạn gặp các sự cố tương tự, có thể không tránh khỏi việc thiết kế lại các bảng và truy vấn kỹ lưỡng hơn.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Giới thiệu về Hadoop và Dữ liệu lớn

  2. Làm thế nào để sử dụng câu lệnh bảng thay thế trong SQL?

  3. Nhóm dữ liệu bằng cách sử dụng hàm OVER và PARTITION BY

  4. Mẹo để thiết kế cơ sở dữ liệu tốt hơn

  5. SQL là gì và làm thế nào để bắt đầu với nó?