2013-06-21 20 views
6

Tôi đang cố gắng sử dụng ZF2 Paginator trên một số bộ hồ sơ lớn (khoảng 10 triệu trong trường hợp xấu nhất với bộ lọc tìm kiếm). Bảng của tôi ở định dạng InnoDB, mà tôi hiểu không giữ một số lượng nhất định như một phần của siêu dữ liệu.Hiệu suất thất thoát cho Count() sử dụng ZF2 Paginator trên InnoDB Tables

Tôi nhận thấy rằng tôi có thể mở rộng lớp Zend \ Paginator \ Adapter \ DbSelect và thực hiện phương thức count() của riêng tôi sử dụng dữ liệu đếm mà tôi lưu trữ theo cách thủ công trong bảng khác, nhưng tôi không chắc chắn về cách lưu trữ số lượng tất cả các hoán vị có thể có của các tìm kiếm có thể được thực hiện.

Giá trị mặc định ZF2 DbSelect adapter sử dụng phương pháp này:

<?php 
public function count() 
{ 
    if ($this->rowCount !== null) { 
     return $this->rowCount; 
    } 

    $select = clone $this->select; 
    $select->reset(Select::LIMIT); 
    $select->reset(Select::OFFSET); 
    $select->reset(Select::ORDER); 

    $countSelect = new Select; 
    $countSelect->columns(array('c' => new Expression('COUNT(1)'))); 
    $countSelect->from(array('original_select' => $select)); 

    $statement = $this->sql->prepareStatementForSqlObject($countSelect); 
    $result = $statement->execute(); 
    $row  = $result->current(); 

    $this->rowCount = $row['c']; 

    return $this->rowCount; 
} 
?> 

Đây là một câu hỏi ví dụ rất đơn giản mà phương pháp sản xuất cho tôi:

SELECT 
    COUNT(1) AS `c` 
FROM 
    (
     SELECT 
      `contacts`.`id` AS `id`, 
      `contacts`.`firstname` AS `firstname`, 
      `contacts`.`middlename` AS `middlename`, 
      `contacts`.`lastname` AS `lastname`, 
      `contacts`.`gender` AS `gender` 
     FROM 
      `contacts` 
     WHERE 
      `contacts`.`trash` = '0' 
    ) AS `original_select` 

Tôi không chắc chắn những gì hiệu suất sẽ là trên MyISAM bảng, nhưng điều này không cho tôi do nó ăn tất cả các không gian có thể giải phóng trên Amazon RDS (25GB, db.m1.small) trường hợp mà nó đang chạy. Như một so sánh, chỉ chạy truy vấn bên trong (bản gốc), nó hoàn thành trong 100 giây (chắc chắn là không tốt) và trả về 7.39 triệu bản ghi.

Dưới đây là giải thích từ truy vấn bên trong (một giải thích về số lượng người ta cũng chết vì không gian đĩa trên máy chủ RDS):

 
+----+-------------+----------+------+---------------+-------+---------+-------+---------+-------+ 
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | 
+----+-------------+----------+------+---------------+-------+---------+-------+---------+-------+ 
| 1 | SIMPLE  | contacts | ref | trash   | trash | 1  | const | 3441317 |  | 
+----+-------------+----------+------+---------------+-------+---------+-------+---------+-------+ 
1 rows in set (0.04 sec) 

Có bất cứ điều gì có thể được thực hiện để điều chỉnh này tốt hơn? Có phải cách mà ZF2 Paginator xử lý đếm không tương thích theo cách nào đó với cách mà InnoDB làm việc không? Làm thế nào những người khác sẽ xử lý bộ nhớ đệm của tất cả các truy vấn có thể nếu chúng tôi cho phép tìm kiếm trên hầu hết các trường trong cơ sở dữ liệu?

Cảm ơn trước ...

+0

Vấn đề này là cố hữu đối với InnoDB, MyISAM không có vấn đề này vì nó theo dõi số lượng hàng trong bảng trong siêu dữ liệu của nó. Nó có lẽ là tốt nhất để chỉ cần tinh chỉnh các truy vấn trong một giao diện người dùng cơ sở dữ liệu và xem những gì có hiệu lực nó. Thay vì COUNT (1) bạn có thể thử COUNT (id) ví dụ hoặc cho MySQL sử dụng một chỉ mục cụ thể bằng cách sử dụng mysql> count count (1) từ ... sử dụng chỉ mục (your_index) – Ruben

+0

** COUNT (1) **: 15 phút 36 giây; ** COUNT (id) **: 18 phút 8.83 giây – jcq

Trả lời

0

Nếu bạn sử dụng truy vấn này để thay thế:

SELECT c from 
( 
    SELECT COUNT(1) AS c 
    from contacts 
    where trash = '0' 
) AS original_select 
2

Bạn không cần chọn từ các truy vấn ban đầu - đây tiêu thụ bộ nhớ của bạn/diskspace!

SELECT count(1) AS `c` 
FROM (
    SELECT 1 
    FROM `contacts` 
    WHERE `trash` = 0 
) AS `original_select` 

Bên cạnh đó:

  • Giả thùng rác chỉ là một giá trị boolean, làm cho nó một boolean không nullable cột và tìm kiếm một int hoặc boolean là đúng/sai

    ALTER TABLE `contacts` CHANGE `trash` `trash` TINYINT(1) NOT NULL 
    
  • Hãy chắc chắn lập chỉ mục cột thùng rác

    ALTER TABLE `contacts` ADD INDEX `TRASH` (`trash`) 
    

Hơn nữa:

  • Pagination bộ kết quả lớn không nhất thiết đòi hỏi một số lượng chính xác: Giả sử chúng ta đang hiển thị 100 mục trên mỗi trang, chúng ta không cần một nút 100000 trang N duy nhất. Thay vào đó, hãy tính toán trang bằng cách sử dụng bù trừ và giới hạn của bạn và chỉ hiển thị các nút duy nhất cho ví dụ:/10 trang tiếp theo và kết hợp nó với một số nút "hiển thị tiếp theo/trước 10 trang".

  • Khi bạn cần khả năng "truy cập trang cuối cùng" tại sao không sử dụng thứ gì đó như thứ tự DESC để đạt được điều gì đó tương tự.

  • Có thực sự là tình huống mà một người nào đó sẽ phân trang qua hàng 10m của bạn không? Có thể cung cấp các bộ lọc nâng cao để giúp người dùng tìm thấy những gì anh ta cần.

Các vấn đề liên quan