Tôi làm việc với SQL Server và Oracle. Có thể có một số ngoại lệ, nhưng đối với những nền tảng đó, câu trả lời chung là dữ liệu và chỉ mục sẽ được cập nhật cùng một lúc.
Tôi nghĩ rằng sẽ rất hữu ích khi phân biệt giữa khi các chỉ mục được cập nhật cho phiên sở hữu giao dịch và cho các phiên khác. Theo mặc định, các phiên khác sẽ không thấy các chỉ mục được cập nhật cho đến khi giao dịch được cam kết. Tuy nhiên, phiên sở hữu giao dịch sẽ thấy ngay các chỉ mục được cập nhật.
Đối với một cách để suy nghĩ về nó, hãy xem xét tại một bảng có khóa chính. Trong SQL Server và Oracle, điều này được thực hiện như một chỉ mục. Hầu hết thời gian chúng tôi muốn ngay lập tức xảy ra lỗi nếu một lỗi INSERT
được thực hiện sẽ vi phạm khóa chính. Để điều đó xảy ra, chỉ mục phải được cập nhật cùng lúc với dữ liệu. Lưu ý rằng các nền tảng khác, chẳng hạn như Postgres, cho phép các ràng buộc hoãn lại chỉ được kiểm tra khi giao dịch được thực hiện.
Đây là bản demo nhanh của Oracle cho thấy một trường hợp phổ biến:
CREATE TABLE X_TABLE (PK INT NULL, PRIMARY KEY (PK));
INSERT INTO X_TABLE VALUES (1);
INSERT INTO X_TABLE VALUES (1); -- no commit
Câu INSERT
lệnh thứ hai đưa ra một lỗi:
Lỗi SQL: ORA-00001: ràng buộc duy nhất (XXXXXX.SYS_C00384850) đã vi phạm
00001.
00000 - "ràng buộc duy nhất (% s.% S) đã vi phạm"
* Nguyên nhân: Một câu lệnh CẬP NHẬT hoặc INSERT đã cố gắng chèn một khóa trùng lặp. Đối với Oracle đáng tin cậy được cấu hình trong chế độ MAC DBMS, bạn có thể thấy thông báo này nếu một mục trùng lặp tồn tại ở một cấp độ khác.
* Hành động: Xóa bỏ giới hạn duy nhất hoặc không chèn phím.
Nếu bạn muốn thấy một hành động cập nhật chỉ mục dưới đây là một bản demo đơn giản trong SQL Server. Đầu tiên tạo ra một bảng hai cột với một triệu hàng và một chỉ số nonclustered trên VAL
cột:
DROP TABLE IF EXISTS X_TABLE_IX;
CREATE TABLE X_TABLE_IX (
ID INT NOT NULL,
VAL VARCHAR(10) NOT NULL
PRIMARY KEY (ID)
);
CREATE INDEX X_INDEX ON X_TABLE_IX (VAL);
-- insert one million rows with N from 1 to 1000000
INSERT INTO X_TABLE_IX
SELECT N, N FROM dbo.Getnums(1000000);
Truy vấn sau đây có thể sử dụng chỉ mục không bao gồm vì chỉ mục là chỉ mục bao trùm cho truy vấn đó. Nó chứa tất cả các dữ liệu cần thiết để thực hiện nó. Như dự kiến không có lợi nhuận được trả lại.
SELECT *
FROM X_TABLE_IX
WHERE VAL = 'A';
Bây giờ, hãy bắt đầu một giao dịch và cập nhật VAL
cho hầu hết tất cả các hàng trong bảng:
BEGIN TRANSACTION
UPDATE X_TABLE_IX
SET VAL = 'A'
WHERE ID <> 1;
Đây là một phần của kế hoạch truy vấn cho điều đó:
Được khoanh tròn màu đỏ là bản cập nhật cho chỉ mục không bao gồm. Được khoanh tròn màu xanh là bản cập nhật cho chỉ mục được nhóm, về cơ bản là dữ liệu của bảng. Mặc dù giao dịch chưa được cam kết, chúng tôi thấy rằng dữ liệu và chỉ mục được cập nhật trong một phần của việc thực hiện truy vấn. Lưu ý rằng bạn sẽ không luôn thấy điều này trong một gói tùy thuộc vào kích thước của dữ liệu liên quan cùng với các yếu tố có thể khác.
Với giao dịch vẫn chưa được cam kết, hãy xem lại SELECT
truy vấn từ phía trên.
SELECT *
FROM X_TABLE_IX
WHERE VAL = 'A';
Trình tối ưu hóa truy vấn vẫn có thể sử dụng chỉ mục và lần này nó ước tính rằng 999999 hàng sẽ được trả về. Thực hiện truy vấn trả về kết quả mong đợi.
Đó là một bản demo đơn giản nhưng hy vọng nó sẽ xóa mọi thứ lên một chút.
Bên cạnh đó, tôi biết một vài trường hợp có thể lập luận rằng một chỉ mục không được cập nhật ngay lập tức. Điều này được thực hiện vì lý do hiệu suất và người dùng cuối sẽ không thể thấy dữ liệu không nhất quán. Ví dụ, đôi khi xóa sẽ không được áp dụng đầy đủ cho một chỉ mục trong SQL Server. Một quá trình nền chạy và cuối cùng làm sạch dữ liệu. Bạn có thể đọc về hồ sơ ma nếu bạn tò mò.