Tại thời điểm nào cơ sở dữ liệu cập nhật các chỉ mục của nó trong một giao dịch?


11

Tôi đang cố gắng hiểu chuỗi các sự kiện trong phần chèn có liên quan đến cả chỉ mục và giao dịch.

Ví dụ, tài liệu Oracle nêu:

Nếu bạn tạo [hoặc có] một hoặc nhiều chỉ mục trước khi tải dữ liệu, thì cơ sở dữ liệu phải cập nhật mọi chỉ mục khi mỗi hàng được chèn.

Nhưng điều gì xảy ra nếu tôi tạo một giao dịch, chèn năm hàng, sau đó cam kết? Là các chỉ mục được cập nhật cho mỗi lần chèn, hoặc chỉ tại điểm cam kết?

Logic cho tôi biết rằng chúng sẽ chỉ được cập nhật tại điểm cam kết, bởi vì một chỉ mục được cập nhật không thể sử dụng được cho đến khi những hồ sơ đó được cam kết. Nhưng điều đó có đúng không?

Nếu vậy, khi tôi có hàng 1m để chèn, để có hiệu suất tốt nhất tôi nên thực hiện một cam kết lớn của tất cả các hàng chứ không phải 10 giao dịch của hồ sơ 100k? Tất nhiên tôi nhận ra điều này có nguy cơ trở lại lớn hơn nếu hàng 999.999 không thành công.

Xin lỗi nếu thuật ngữ của tôi là một chút ra. Tôi không phải là một DBA bằng thương mại. Tôi không quan tâm lắm đến một cơ sở dữ liệu cụ thể, vì các cơ sở dữ liệu nói chung, mặc dù Oracle và Postgres là những gì tôi sử dụng nhiều nhất. Tôi đã tìm kiếm về chủ đề này nhưng thực sự không thể tìm thấy câu trả lời dứt khoát.

Câu trả lời:


8

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 INSERTlệ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 VALcộ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';

truy vấn 1

Bây giờ, hãy bắt đầu một giao dịch và cập nhật VALcho 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 đó:

truy vấn 2

Đượ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 SELECTtruy vấn từ phía trên.

SELECT *
FROM X_TABLE_IX
WHERE VAL = 'A';

nhập mô tả hình ảnh ở đây

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ò.


Đó là một câu trả lời siêu hạng - và cũng trả lời một điều khác mà tôi đã tự hỏi: liệu một vi phạm khóa chính (hoặc tương tự) sẽ xảy ra trên Chèn hoặc trên Cam kết. Cảm ơn cho một phản ứng đầy đủ như vậy.
Đánh dấu Ireland

Câu hỏi liên quan (về việc khi nào vi phạm ràng buộc sẽ xảy ra) có liên quan đến việc bạn có sử dụng giao dịch hoãn lại hay không. SQL Server chẳng hạn, đã không thực hiện giao dịch hoãn lại, vì vậy tất cả các vi phạm xảy ra ở cuối báo cáo. Các DBMS khác có (ví dụ Postgres, mặc dù không phải cho tất cả các loại ràng buộc), vì vậy khi bạn bị ràng buộc hoãn lại, vi phạm sẽ được kiểm tra ở giai đoạn cam kết của giao dịch).
ypercubeᵀᴹ

Oracle cũng hỗ trợ các ràng buộc hoãn lại
BobC

1

Kinh nghiệm của tôi là chèn hàng 1.000.000 thực sự sẽ đòi hỏi nhiều tài nguyên hơn và mất nhiều thời gian hơn để hoàn thành so với khi bạn sử dụng một đợt chèn. Điều này có thể được thực hiện, ví dụ, thành 100 lần chèn 10.000 hàng.

Điều này làm giảm chi phí của các lô được chèn và nếu một lô bị lỗi thì đó là một rollback nhỏ hơn.

Trong mọi trường hợp, đối với SQL Server, có một tiện ích bcp hoặc lệnh BULK INSERT có thể được sử dụng để thực hiện chèn hàng loạt.

Và, tất nhiên, bạn cũng có thể triển khai mã riêng của mình để xử lý phương pháp này.


1
Nói chung, nếu bạn cần chèn một số lượng lớn các hàng trên một bảng cần một chỉ mục, thì có khả năng nhanh hơn để thả chỉ mục, tải dữ liệu và sau đó xây dựng lại chỉ mục. Oracle cũng hỗ trợ tùy chọn tải hàng loạt đường dẫn trực tiếp, sử dụng gợi ý / * + APPEND * /.
BobC
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.