Đọc dữ liệu trong Odoo có ba phương thức hay dùng, và người mới thường chỉ biết search rồi dùng nó cho mọi thứ. Nhưng dùng đúng phương thức cho đúng nhu cầu vừa gọn code vừa nhanh hẳn. Nối tiếp create và write, bài này so sánh search, search_count, search_read.

Ba phương thức, ba kiểu trả về

Điểm khác biệt cốt lõi: chúng trả về những thứ khác nhau, và thứ trả về quyết định chi phí.

Bảng so sánh ba cách truy vấn trong Odoo 19 trả về khác nhau hiệu năng khác nhau: search domain trả về recordset là object ORM dùng khi cần thao tác tiếp như write gọi method đọc quan hệ; search_count domain trả về số nguyên int dùng khi chỉ cần đếm không nạp bản ghi; search_read domain fields trả về list các dict dùng khi chỉ cần đọc vài trường cho báo cáo API RPC JSON; ví dụ P.search với is_company True trả res.partner 15 24 6 1 10 23, P.search_count với is_company True trả 6, P.search_read với is_company True và list name city limit 2 trả list hai dict gồm id 15 name Cà Phê Việt Chi nhánh Hà Nội city Hà Nội và id 24 name Công ty Cà Phê Tây Nguyên city Gia Lai; bẫy là cần đếm mà viết len search sẽ nạp cả nghìn bản ghi chỉ để đếm hãy dùng search_count

Hình 1: search trả recordset (object ORM đầy đủ — thao tác tiếp được). search_count trả số nguyên (chỉ đếm). search_read trả list dict (chỉ những trường bạn xin). Chọn phương thức = chọn đúng lượng công việc cần làm.

Đo thật: search_count vs len(search)

Bẫy phổ biến nhất: cần đếm mà viết len(search([...])). Điều đó bắt Odoo nạp toàn bộ bản ghi thành recordset rồi mới đếm. Đây là số đo thật trên 3030 bản ghi res.partner:

Đo hiệu năng thật trên 3030 bản ghi res.partner database blog19: cùng đếm tất cả bằng hai cách, P.search_count list rỗng trả về 3030 mất 0.0006 giây chỉ chạy SELECT count sao, còn len của P.search list rỗng trả về 3030 mất 0.0010 giây vì nạp 3030 recordset rồi đếm; khung nhấn search_count nhanh hơn 1.6 lần và không tốn bộ nhớ nạp bản ghi; search_read một truy vấn trả thẳng dict không dựng object ORM, P.search_read list rỗng với name city trả về list các dict id name city sẵn sàng cho JSON RPC; ghi chú càng nhiều bản ghi search_count càng thắng đậm so với len search

Hình 2: Số đo thật. search_count([]) chỉ chạy một câu SELECT count(*) — 0.0006 giây. Còn len(search([])) phải nạp cả 3030 recordset rồi đếm — 0.0010 giây, chậm 1.6 lần và tốn bộ nhớ dựng object. Trên bảng vài trăm nghìn dòng, khác biệt này là giây với chục giây, chưa kể RAM.

Khi nào dùng cái nào

search — khi cần làm gì đó với bản ghi

orders = env['sale.order'].search([('state', '=', 'draft')])
orders.action_confirm()        # gọi method, write, đọc quan hệ...

Chỉ dùng search khi bạn thực sự cần recordset để thao tác tiếp. Nó nạp object ORM đầy đủ (đắt nhất trong ba cái).

search_count — khi chỉ cần một con số

if env['sale.order'].search_count([('state', '=', 'draft')]) > 100:
    self.canh_bao_ton_dong()

Badge đếm, điều kiện "có quá N bản ghi không", thống kê nhanh — luôn dùng search_count, đừng bao giờ len(search(...)).

search_read — khi chỉ cần đọc vài trường

data = env['res.partner'].search_read(
    [('is_company', '=', True)],
    ['name', 'email', 'city'],       # chỉ lấy 3 trường
    limit=20,
)
# data = [{'id':.., 'name':.., 'email':.., 'city':..}, ...]

search_read gộp "tìm + đọc" thành một lời gọi và trả thẳng list dict — không dựng object ORM. Cực hợp cho báo cáo, API/RPC, xuất JSON: bạn cần dữ liệu thô để trả về client, không cần method của model. Đây cũng chính là phương thức mà giao diện web Odoo gọi để nạp danh sách.

Vài tinh chỉnh chung

Cả ba đều nhận thêm tham số điều khiển kết quả:

P.search(domain, limit=10, offset=20, order='name desc')
  • limit: số bản ghi tối đa (phân trang).
  • offset: bỏ qua N bản ghi đầu (trang thứ mấy).
  • order: sắp xếp ('create_date desc'); mặc định theo _order của model.

search_count bỏ qua limit/offset/order (đếm thì không cần), còn search và search_read dùng đủ.

Nhớ ba ý

  1. search trả recordset (thao tác tiếp), search_count trả số (chỉ đếm), search_read trả list dict (chỉ đọc trường) — chọn đúng cái để làm đúng lượng việc.
  2. Đừng len(search([...])) để đếm — đo thật search_count nhanh 1.6 lần trên 3030 bản ghi và không tốn RAM nạp object; chênh lệch giãn mạnh khi bảng lớn.
  3. search_read gộp tìm + đọc thành một lời gọi, trả dict thô — lý tưởng cho báo cáo, API, JSON; dùng limit/offset/order để phân trang và sắp xếp.

Ba phương thức đều nhận domain làm điều kiện lọc. Phần sau đào sâu cú pháp domain — dạng [(field, op, value)], các toán tử, và cách viết điều kiện lọc cho đúng.