Giảm thiểu số lần đọc được lập chỉ mục với các tiêu chí phức tạp


12

Tôi đang tối ưu hóa cơ sở dữ liệu của Firebird 2.5 về vé làm việc. Chúng được lưu trữ trong một bảng được khai báo như sau:

CREATE TABLE TICKETS (
  TICKET_ID id PRIMARY KEY,
  JOB_ID id,
  ACTION_ID id,
  STATUS str256 DEFAULT 'Pending'
);

Tôi thường muốn tìm vé đầu tiên chưa được xử lý và đang ở Pendingtrạng thái.

Vòng lặp xử lý của tôi sẽ là:

  1. Lấy vé thứ 1 ở đâu Pending
  2. Làm việc với vé.
  3. Cập nhật tình trạng vé => Complete
  4. Nói lại.

Không có gì quá lạ mắt. Nếu tôi đang xem cơ sở dữ liệu trong khi vòng lặp này chạy, tôi sẽ thấy số lần đọc được lập chỉ mục cho mỗi lần lặp. Hiệu suất dường như không suy giảm khủng khiếp mà tôi có thể nói, nhưng máy tôi đang thử nghiệm khá nhanh. Tuy nhiên, tôi đã nhận được báo cáo về sự suy giảm hiệu suất theo thời gian từ một số người dùng của tôi.

Tôi đã có một chỉ mục trên Status, nhưng có vẻ như nó quét xuống Ticket_Idcột mỗi lần lặp. Có vẻ như tôi đang xem xét một cái gì đó, nhưng tôi không chắc chắn những gì. Là số lần leo lên của các lần đọc được lập chỉ mục cho một cái gì đó như thế này dự kiến, hoặc là chỉ số đang hoạt động sai theo một cách nào đó?

- Chỉnh sửa cho ý kiến ​​-

Trong Firebird, bạn giới hạn truy xuất hàng như:

Select First 1
  Job_ID, Ticket_Id
From
  Tickets
Where
  Status = 'Pending'

Vì vậy, khi tôi nói "đầu tiên", tôi chỉ yêu cầu nó cho một hồ sơ giới hạn được thiết lập ở đâu Status = 'Pending'.


Bạn có ý nghĩa gì với "lần đầu tiên" trong "Lấy vé đầu tiên trong đó 'Đang chờ'" ?
ypercubeᵀᴹ

Nếu "đầu tiên" có nghĩa là nhỏ nhất ticket_id, thì bạn có thể cần một chỉ số trên(status, ticket_id)
ypercubeᵀᴹ

Và bạn có chắc chắn rằng sự xuống cấp hiệu suất là do thủ tục này gây ra chứ không phải do các truy vấn / câu lệnh khác không?
ypercubeᵀᴹ

@ypercube - Không, tôi không chắc đó là nơi suy giảm hiệu suất. Đó là lý do tại sao câu hỏi của tôi là "tôi có cần phải quan tâm đến vấn đề này không, hay đó là hành vi bình thường của một chỉ số?". Đó là điều tôi nhận thấy khi theo dõi cơ sở dữ liệu và tôi cho rằng điều đó thật bất ngờ. Tôi không mong đợi nó sẽ tiếp tục quét các hàng trước khi tôi cung cấp một mệnh đề where đối với một cột được lập chỉ mục. FWIW, sửa đổi chỉ mục để bao gồm ticket_idthực sự hoạt động kém hơn so với việc chỉ có Trạng thái được lập chỉ mục.
gddc

id(kiểu dữ liệu) là một miền bạn xác định?
a_horse_with_no_name

Câu trả lời:


1

Sự xuống cấp theo thời gian xảy ra do số lượng vật phẩm tăng ở trạng thái "Hoàn thành". Hãy suy nghĩ về điều này trong một giây - bạn sẽ không nhận được bất kỳ sự suy giảm hiệu suất nào khi thử nghiệm vì bạn có thể có một số lượng nhỏ hàng với trạng thái là "Hoàn thành". Nhưng trong sản xuất, họ có thể có hàng triệu hàng với trạng thái "Hoàn thành" và con số này sẽ tăng theo thời gian. Điều này, về cơ bản, làm cho chỉ mục của bạn trên Status ngày càng ít hữu ích hơn theo thời gian. Như vậy, cơ sở dữ liệu có thể chỉ quyết định rằng vì Status hầu như luôn có giá trị 'Hoàn thành', nên nó sẽ chỉ quét bảng thay vì sử dụng chỉ mục.

Trong SQL Server (và có thể các RDBMS khác?), Điều này có thể được xử lý bằng cách sử dụng Chỉ mục được lọc. Trong SQL Server, bạn sẽ thêm một điều kiện WHERE vào cuối định nghĩa chỉ mục của bạn để nói "chỉ áp dụng chỉ mục này cho các bản ghi có Trạng thái <> 'Hoàn thành'". Sau đó, bất kỳ truy vấn nào sử dụng vị từ này rất có thể sẽ sử dụng chỉ mục trên số lượng nhỏ các bản ghi không được đặt thành 'Hoàn thành'. Tuy nhiên, dựa trên tài liệu ở đây: http://www.firebirdsql.org/refdocs/langrefupd25-ddl-index.html , có vẻ như Firebird không hỗ trợ các chỉ mục được lọc.

Cách giải quyết là đặt các bản ghi 'Hoàn thành' vào bảng ArchiveTickets. Tạo một bảng có cùng định nghĩa chính xác (mặc dù không có bất kỳ ID được tạo tự động nào) như bảng Vé của bạn và duy trì các hàng giữa chúng bằng cách đẩy các bản ghi 'Hoàn thành' vào bảng ArchiveTickets. Chỉ số trên bảng Vé của bạn sau đó sẽ có số lượng hồ sơ nhỏ hơn nhiều và hiệu suất cao hơn nhiều. Điều này có thể có nghĩa là bạn sẽ cần thay đổi bất kỳ báo cáo nào, v.v. tham chiếu vé 'Hoàn thành' để trỏ đến bảng Lưu trữ hoặc thực hiện UNION trên cả Vé và Lưu trữ Lưu trữ. Điều này sẽ có lợi thế là không chỉ nhanh mà còn có nghĩa là bạn có thể tạo các chỉ mục cụ thể cho bảng ArchiveTickets để làm cho nó hoạt động tốt hơn cho các truy vấn khác (ví dụ:

Bạn nên quan tâm đến điều này nếu sản phẩm của bạn sẽ đi vào hàng ngàn hàng. Hiệu suất sẽ giảm dần theo thời gian và tác động tiêu cực đến trải nghiệm người dùng của bạn.


0

Hiệu suất có bị ảnh hưởng hay không sẽ là một chức năng của khối lượng dữ liệu và công suất máy. Với khả năng của phần cứng hiện đại, thật khó để tưởng tượng khối lượng bán vé không thể xử lý theo thiết kế mà bạn mô tả. Tuy nhiên, có những thay đổi tôi muốn đề xuất cho chính xác và có thể cải thiện hiệu suất như một lợi ích thứ cấp.

Truy vấn chờ xử lý đầu tiên của bạn là không xác định. Đầu tiên theo thứ tự nào? Một bảng SQL không có thứ tự nội tại; các First 1Hack chỉ là đem lại cho bạn một số đầu tiên tùy ý. Để làm cho nó mang tính quyết định, tại sao không xử lý các công việc đang chờ xử lý theo thứ tự Job_ID?

Nếu bạn có hai chỉ mục {Job_ID} và {Status, Job_ID}, truy vấn này sẽ trả về một hàng có thể dự đoán và hiệu quả:

Select Job_ID, Ticket_Id
From   Tickets
Where Job_ID = ( 
  select min(Job_ID) from Tickets 
  where Status = 'Pending'
);

Tôi không phải là người dùng Firebird, vì vậy bạn sẽ phải kiểm tra gói truy vấn, nhưng nó sẽ hiệu quả vì truy vấn phụ chỉ tham số thứ hai, tạo ra giá trị cho cái đầu tiên. (Có thể có các thủ thuật hiệu quả khác có sẵn cho bạn. Chẳng hạn, bạn có thể tổ chức bảng vật lý dưới dạng cây B + hoặc có quyền truy cập vào một row_id ẩn chẳng hạn.)

Sự thay đổi khác mà tôi sẽ thực hiện cho chính xác là tạo Statusmột byte đơn, bị ràng buộc và để ứng dụng cung cấp chuỗi "Đang chờ xử lý". Điều đó sẽ bảo vệ chống lại các Statusgiá trị sai lầm , và có thể làm cho chỉ số nhỏ hơn trong mặc cả. Cái gì đó như:

CREATE TABLE TICKETS (
  TICKET_ID id PRIMARY KEY,
  JOB_ID id,
  ACTION_ID id,
  STATUS char(1) not NULL 
     DEFAULT 'P'
     CHECK( STATUS in ('P', 'C', 'X') ) -- whatever the domain is
);

Tất nhiên, bạn có thể sử dụng chế độ xem (hoặc có thể là cột dẫn xuất) để cung cấp các chuỗi chính tắc cho Trạng thái.

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.