2012-02-14 36 views
7

Tôi đã suy nghĩ về điều này một thời gian và nó đã đến một điểm mà tôi nghĩ tốt hơn là nên hỏi xung quanh và lắng nghe những gì người khác nghĩ.Đánh số chính xác với sự tham gia trái

Im phình hệ thống lưu trữ vị trí trên Mysql. Mỗi vị trí đều có một loại và một số vị trí có nhiều địa chỉ.

Các bảng giống như thế này

location 
    - location_id (autoincrement) 
    - location_name 
    - location_type_id 

location_types 
    - type_id 
    - type_name (For example "Laundry") 

location_information 
    - location_id (Reference to the location table) 
    - location_address 
    - location_phone 

Vì vậy, nếu tôi muốn truy vấn cơ sở dữ liệu trong 10 gần đây nhất thêm tôi sẽ đi với một cái gì đó như thế này:

SELECT l.location_id, l.location_name, 
     t.type_id, t.type_name, 
     i.location_address, i.location_phone 
FROM location AS l 
LEFT JOIN location_information AS i ON (l.location_id = i.location_id) 
LEFT JOIN location_types AS t ON (l.location_type_id = t.type_id) 
ORDER BY l.location_id DESC 
LIMIT 10 

Phải không? Nhưng vấn đề là nếu một địa điểm có nhiều hơn 1 địa chỉ giới hạn/pagination sẽ không được accurrate, trừ khi tôi "GROUP BY l.location_id", nhưng điều đó sẽ chỉ hiển thị một địa chỉ cho mỗi địa điểm. với những địa điểm có nhiều địa chỉ?

Vì vậy, tôi nghĩ rằng cách duy nhất để giải quyết điều này bằng cách thực hiện một truy vấn bên trong một vòng lặp .. Một cái gì đó như thế này (giả):

$db->query('SELECT l.location_id, l.location_name, 
      t.type_id, t.type_name 
      FROM location AS l 
      LEFT JOIN location_types AS t ON (l.location_type_id = t.type_id) 
      ORDER BY l.location_id DESC 
      LIMIT 10'); 

$locations = array(); 
while ($row = $db->fetchRow()) 
{ 
    $db->query('SELECT i.location_address, i.location_phone 
       FROM location_information AS i 
       WHERE i.location_id = ?', $row['location_id']); 

    $locationInfo = $db->fetchAll(); 
    $locations[$row['location_id']] = array('location_name' => $row['location_name'], 
              'location_type' => $row['location_type'], 
              'location_info' => $locationInfo); 

} 

Bây giờ im nhận được 10 địa điểm cuối cùng, nhưng bằng cách làm mà tôi kết thúc với ít nhất 10 truy vấn nhiều hơn và tôi không nghĩ điều đó sẽ giúp hiệu suất ứng dụng.

Có cách nào tốt hơn để đạt được những gì tôi đang tìm kiếm không? (phân trang chính xác).

+0

Địa chỉ nào (bản ghi địa phương_information) bạn muốn trả lại cho một địa điểm? Nếu bạn có thể nói cái nào bạn muốn, chúng tôi có thể nói với máy tính bạn muốn cái nào. –

Trả lời

17

Đây là truy vấn ban đầu của bạn

SELECT l.location_id, l.location_name, 
     t.type_id, t.type_name, 
     i.location_address, i.location_phone 
FROM location AS l 
LEFT JOIN location_information AS i ON (l.location_id = i.location_id) 
LEFT JOIN location_types AS t ON (l.location_type_id = t.type_id) 
ORDER BY l.location_id DESC 
LIMIT 10 

Bạn thực hiện pagination ngoái. Nếu bạn cấu trúc lại truy vấn này, bạn có thể thực hiện phân trang trước đó.

SELECT l.location_id, l.location_name, 
     t.type_id, t.type_name, 
     i.location_address, i.location_phone 
FROM 
    (SELECT location_id,location_type_id FROM location 
    ORDER BY location_id LIMIT 10) AS k 
    LEFT JOIN location AS l ON (k.location_id = l.location_id) 
    LEFT JOIN location_information AS i ON (k.location_id = i.location_id) 
    LEFT JOIN location_types AS t ON (l.location_type_id = t.type_id) 
; 

Lưu ý Tôi đã tạo truy vấn con được gọi là k. 10 phím được chọn và ra lệnh cho FIRST !!!

Sau đó, JOIN có thể tiếp tục từ đó, hy vọng chỉ sử dụng 10 location_ids.

Điều gì sẽ giúp subquery k là một chỉ số mang location_id và location_type_id

ALTER TABLE location ADD INDEX id_type_ndx (location_id,location_type_id); 

Đây là cái gì khác bạn có thể thích về phương pháp này

Làm thế nào để bạn truy vấn trong 10 ids tiếp theo (id 11 - 20)? Như thế này:

SELECT l.location_id, l.location_name, 
     t.type_id, t.type_name, 
     i.location_address, i.location_phone 
FROM 
    (SELECT location_id,location_type_id FROM location 
    ORDER BY location_id LIMIT 10,10) AS k 
    LEFT JOIN location AS l ON (k.location_id = l.location_id) 
    LEFT JOIN location_information AS i ON (k.location_id = i.location_id) 
    LEFT JOIN location_types AS t ON (l.location_type_id = t.type_id) 
; 

Tất cả bạn phải làm là thay đổi các điều khoản trong LIMIT subquery k với mỗi trang mới.

  • LIMIT 20,10
  • LIMIT 30,10
  • và vân vân ...

tôi có thể cải thiện refactoring bằng cách loại bỏ các bảng vị trí và có subquery k mang theo các lĩnh vực cần thiết như thế này:

SELECT k.location_id, k.location_name, 
     t.type_id, t.type_name, 
     i.location_address, i.location_phone 
FROM 
    (SELECT location_id,location_type_id,location_name 
    FROM location ORDER BY location_id LIMIT 10,10) AS k 
    LEFT JOIN location_information AS i ON (k.location_id = i.location_id) 
    LEFT JOIN location_types AS t ON (k.location_type_id = t.type_id) 
; 

Làm cho chỉ mục bổ sung đó sẽ không cần thiết cho phiên bản này.

Hãy thử!

+0

Với thực tế sử dụng LIMIT tăng có thể tốn kém sau một số trang, ý tưởng chính là tốt. – Alfabravo

+0

Cảm ơn bạn! Đây là loại truy vấn tôi đang tìm kiếm, không bao giờ vượt qua tâm trí của tôi để làm một truy vấn phụ như thế này! – mpratt

2

Có một vài cách để giải quyết việc này:

  • Bạn có thể thêm một cột IsPrimary chút vào bảng location_information, và thêm một kích hoạt để đảm bảo mỗi vị trí luôn luôn chỉ có một location_information kỷ lục với bộ này đến 1
  • Bạn có thể chọn bản ghi cũ nhất hoặc mới nhất location_information (MIN/MAX), sử dụng cột location_id nếu bạn không có các cột DateCreated hoặc DateModified.
3

tốt hơn so với vòng lặp và 10 thắc mắc, bạn có thể truy vấn cho giới hạn location.location_id 10 cho pagination, nối đó vào một chuỗi dấu phẩy tách ra và sau đó truy vấn đầy đủ để có được WHERE location.location_id IN (1,2,3...{list of ids})

3

Bạn có thể đi với suy nghĩ ban đầu của bạn về việc nhóm theo location_id và sau đó sử dụng hàm group_concat để hiển thị tất cả các địa chỉ cho vị trí đó dưới dạng 1 trường.

SELECT l.location_id, l.location_name, 
    t.type_id, t.type_name, 
    group_concat(concat("Address: ",i.location_address, " Phone: ", i.location_phone)) as addresses 
FROM location AS l 
LEFT JOIN location_information AS i ON (l.location_id = i.location_id) 
LEFT JOIN location_types AS t ON (l.location_type_id = t.type_id) 
GROUP BY l.location_id 
ORDER BY l.location_id DESC 
LIMIT 10 
Các vấn đề liên quan