2012-04-14 27 views
5

Tôi có truy vấn này để thu thập thông tin về một đơn hàng và nó trở nên khá phức tạp.MySQL Có giới hạn nào đối với InnerJoin không?

Tôi không có bất kỳ dữ liệu nào để kiểm tra vì vậy tôi hỏi, nếu có ai có kinh nghiệm với bộ dữ liệu nhỏ và lớn, có giới hạn về số lượng tham gia bạn có thể hoặc nên thực hiện trong một truy vấn ? Nó sẽ được khuyến khích để phân chia các truy vấn lớn thành các phần nhỏ hơn hoặc không làm cho một sự khác biệt đáng kể?

Ngoài ra, pháp lý có mệnh đề WHERE sau mỗi INNER JOIN phải không?

Cảm ơn lời khuyên của bạn.

Đây là truy vấn:

# Order: Get Order 

function getOrder($order_id) { 
    $sql = "SELECT (order.id, order.created, o_status.status, 
        /* payment info */ 
        order.total, p_status.status, 
        /* ordered by */ 
        cust_title.title, cust.forename, cust.surname, 
        customer.phone, customer.email, 
        cust.door_name, cust.street1, 
        cust.street2, cust.town, 
        cust.city, cust.postcode, 
        /* deliver to */ 
        recip_title.title, recipient.forename, recipient.surname, 
        recipient.door_name, recipient.street1, 
        recipient.street2, recipient.town, 
        recipient.city, recipient.postcode, 
        /* deliver info */ 
         shipping.name, order.memo, 
        /* meta data */ 
        order.last_update) 
       FROM tbl_order AS order 

     INNER JOIN tbl_order_st AS o_status 
       ON order.order_status_id = o_status.id 

     INNER JOIN tbl_payment_st AS p_status 
       ON order.payment_status_id = p_status.id 

     INNER JOIN (SELECT (cust_title.title, cust.forename, cust.surname, 
          customer.phone, customer.email, 
     /* ordered by */ cust.door_name, cust.street1, 
          cust.street2, cust.town, 
          cust.city, cust.postcode) 
         FROM tbl_customer AS customer 
       INNER JOIN tbl_contact AS cust 
          ON customer.contact_id = cust.id 
       INNER JOIN tbl_contact_title AS cust_title 
         ON cust.contact_title_id = cust_title.id 
        WHERE order.customer_id = customer.id) 
       ON order.customer_id = customer.id 

     INNER JOIN (SELECT (recip_title.title, recipient.forename, recipient.surname, 
     /* deliver to */ recipient.door_name, recipient.street1, 
          recipient.street2, recipient.town, 
          recipient.city, recipient.postcode) 
         FROM tbl_contact AS recipient 
       INNER JOIN tbl_contact_title AS recip_title 
         ON recipient.contact_title_id = recip_title.id 
        WHERE order.contact_id = recipient.id) 
       ON order.contact_id = recipient.id 

     INNER JOIN tbl_shipping_opt AS shipping 
       ON order.shipping_option_id = shipping.id 

      WHERE order.id = '?';"; 
    dbQuery($sql, array((int)$order_id)); 
    $rows = dbRowsAffected(); 
    if ($rows == 1) 
     return dbFetchAll(); 
    else 
     return null; 
} 

Kể từ khi một người nào đó yêu cầu các schema cho truy vấn này, ở đây nó là:

# TBL_CONTACT_TITLE 

DROP TABLE IF EXISTS tbl_contact_title; 
CREATE TABLE tbl_contact_title(
    id INT NOT NULL AUTO_INCREMENT, 
    PRIMARY KEY(id), 
    title CHAR(3) 
) ENGINE = InnoDB; 
INSERT INTO tbl_contact_title 
    (title) 
VALUES ('MR'), 
    ('MRS'), 
    ('MS'); 


# TBL_CONTACT 

DROP TABLE IF EXISTS tbl_contact; 
CREATE TABLE tbl_contact(
    id INT NOT NULL AUTO_INCREMENT, 
    PRIMARY KEY(id), 
    contact_title_id INT, 
    FOREIGN KEY(contact_title_id) REFERENCES tbl_contact_title(id) ON DELETE SET NULL, 
    forename VARCHAR(50), 
    surname VARCHAR(50), 
    door_name VARCHAR(25), 
    street1 VARCHAR(40), 
    street2 VARCHAR(40), 
    town VARCHAR(40), 
    city VARCHAR(40), 
    postcode VARCHAR(10), 
    currency_id INT, 
    FOREIGN KEY(currency_id) REFERENCES tbl_currency(id) ON DELETE SET NULL 
) ENGINE = InnoDB; 

# TBL_CUSTOMER 

DROP TABLE IF EXISTS tbl_customer; 
CREATE TABLE tbl_customer(
    id INT NOT NULL AUTO_INCREMENT, 
    PRIMARY KEY(id), 
    contact_id INT, 
    FOREIGN KEY(contact_id) REFERENCES tbl_contact(id) ON DELETE SET NULL, 
    birthday DATE, 
    is_male TINYINT, 
    phone VARCHAR(20), 
    email VARCHAR(50) NOT NULL 
) ENGINE = InnoDB, AUTO_INCREMENT = 1000; 

# TBL_ORDER_ST 

DROP TABLE IF EXISTS tbl_order_st; 
CREATE TABLE tbl_order_st(
    id INT NOT NULL AUTO_INCREMENT, 
    PRIMARY KEY(id), 
    status VARCHAR(25) 
) ENGINE = InnoDB; 
INSERT INTO tbl_order_st 
    (status) 
VALUES 
    ('NEW'), 
    ('PROCESSING'), 
    ('SHIPPED'), 
    ('COMPLETED'), 
    ('CANCELLED'); 


# TBL_SHIPPING_OPT 

DROP TABLE IF EXISTS tbl_shipping_opt; 
CREATE TABLE tbl_shipping_opt(
    id INT NOT NULL AUTO_INCREMENT, 
    PRIMARY KEY(id), 
    name VARCHAR(50), 
    description VARCHAR(255), 
    cost DECIMAL(6,3) 
) ENGINE = InnoDB; 
INSERT INTO tbl_shipping_opt 
    (name, description, cost) 
VALUES 
    ('UK Premier', 'U.K. Mainland upto 30KG, Next Working Day', 8.00), 
    ('Europe Standard', 'Most European Destinations* upto 30KG, 2 to 5 Working Days *please check before purchase', 15.00); 


# TBL_PAYMENT_ST 

DROP TABLE IF EXISTS tbl_payment_st; 
CREATE TABLE tbl_payment_st(
    id INT NOT NULL AUTO_INCREMENT, 
    PRIMARY KEY(id), 
    status VARCHAR(25) 
) ENGINE = InnoDB; 
INSERT INTO tbl_payment_st 
    (status) 
VALUES 
    ('UNPAID'), 
    ('PAID'); 


# TBL_ORDER 

DROP TABLE IF EXISTS tbl_order; 
CREATE TABLE tbl_order(
    id INT NOT NULL AUTO_INCREMENT, 
    PRIMARY KEY(id), 
    customer_id INT, 
     FOREIGN KEY(customer_id) REFERENCES tbl_customer(id) ON DELETE SET NULL, 
    contact_id INT, 
    FOREIGN KEY(contact_id) REFERENCES tbl_contact(id) ON DELETE SET NULL, 
    created DATETIME, 
    last_update TIMESTAMP, 
    memo VARCHAR(255), 
    order_status_id INT, 
    FOREIGN KEY(order_status_id) REFERENCES tbl_order_st(id), 
    shipping_option_id INT, 
    FOREIGN KEY(shipping_option_id) REFERENCES tbl_shipping_opt(id), 
    coupon_id INT, 
    FOREIGN KEY(coupon_id) REFERENCES tbl_coupon(id) ON DELETE SET NULL, 
    total DECIMAL(9,3), 
    payment_status_id INT, 
    FOREIGN KEY(payment_status_id) REFERENCES tbl_payment_st(id) 
) ENGINE = InnoDB, AUTO_INCREMENT = 1000; 
+2

Đẩy giá thầu lên giá thầu CPC Miễn là bạn không nhận được bất kỳ lỗi cú pháp hoặc một cái gì đó như "quá nhiều tham gia", hãy tiếp tục. – hakre

+0

@hakre Cảm ơn ... Tôi lấy nó sau đó, kích thước của truy vấn không quan trọng. – Ozzy

Trả lời

3

Bạn không có bất kỳ nơi nào gần giới hạn JOIN cho MySQL. Số lần tham gia của bạn không tệ. Tuy nhiên, việc tham gia vào một bảng có nguồn gốc (truy vấn con bên trong) của bạn khi bạn đang làm có thể gây ra các vấn đề về hiệu suất, vì các bảng dẫn xuất không có các chỉ mục. Thực hiện một tham gia trên một bảng có nguồn gốc mà không có chỉ mục có thể được làm chậm.

Bạn nên cân nhắc tạo một bảng tạm thời thực với các chỉ mục để tham gia hoặc tìm ra cách để tránh truy vấn phụ.

JOIN trong MySQL về cơ bản giống như thực hiện tìm kiếm (tìm kiếm) cho mỗi hàng được nối. Vì vậy, MySQL sẽ phải thực hiện nhiều tra cứu nếu bạn đang tham gia nhiều hồ sơ. Đó là ít hơn về bao nhiêu bảng bạn tham gia hơn số hàng mà bạn tham gia có thể là một vấn đề.

Dù sao, MySQL sẽ chỉ thực hiện rất nhiều tìm kiếm trước khi nó sẽ bỏ cuộc và chỉ đọc toàn bộ bảng. Nó làm một công việc khá tốt khi quyết định cái nào sẽ rẻ hơn.

Có lẽ điều tốt nhất bạn có thể làm là giúp nó đoán bằng cách cập nhật thống kê chỉ mục với BẢNG ANALYZE.

Bạn có thể có một mệnh đề WHERE trên mỗi SELECT. Vì vậy, truy vấn con bên trong của bạn sẽ có mệnh đề WHERE và truy vấn bên ngoài của bạn sẽ có mệnh đề WHERE, và chúng được áp dụng sau JOIN (ít nhất là logic, mặc dù MySQL thường sẽ áp dụng chúng đầu tiên cho hiệu suất).

Ngoài ra, tất cả điều này là giả sử bạn biết cách sử dụng đúng chỉ mục.

+0

Tôi rất sẵn lòng chấp nhận câu trả lời này. Tôi có thể chỉ cần tạo một bảng khác (như bạn đề nghị) nếu tôi có vấn đề về hiệu suất nhưng tôi sẽ để nó như bây giờ. Tôi không có kiến ​​thức về lập chỉ mục ... Tôi sẽ phải đọc một số tuts. Cảm ơn @ marcus-adams – Ozzy

1

tôi không có bất kỳ lời khuyên chung, chỉ expirience của riêng tôi.

Tôi đã từng gặp sự cố với hiệu suất rất kém, trong đó tôi đã thêm hàng tấn bảng bằng JOIN. Đã khoảng 20 THAM GIA tôi đã làm. Khi tôi gỡ bỏ một vài JOINS trong một thử nghiệm, tốc độ tăng lên một lần nữa. Do thực tế tôi chỉ cần thông tin duy nhất tôi đã có thể thay thế hầu hết các JOINS với các lựa chọn phụ. Điều này giải quyết vấn đề của tôi từ 25 giây cho truy vấn của tôi xuống ít hơn 1 giây.

Đây có thể là một thực tế về thiết kế bảng, số lượng cột của các bảng đã nối và các chỉ mục của bạn trên phần được nối với các điều khoản.

+0

Vì vậy, bạn đang nói rằng tôi có thể có các truy vấn lớn nhưng sub-SELECT là cách nhanh hơn cú pháp JOIN? – Ozzy

+1

Tôi nghĩ nó phụ thuộc vào chính truy vấn. Trong trường hợp của tôi, sub chọn cách nhanh hơn với thiết lập chỉ mục phù hợp. – YvesR

+0

Tôi nghĩ bạn nên THAM GIA tất cả những gì bạn cần và sau đó bắt đầu đơn giản hóa nó (phụ chỉ chọn cho dữ liệu cột 1 và kết hợp cùng một dữ liệu) – YvesR

2

Tôi đã từng thử bản thân mình để xem giới hạn số lần tham gia và tôi đã thử nghiệm tham gia với 100 bảng trên mysql 5.0.4 nếu tôi nhớ lại chính xác.

tôi đã được đưa ra các lỗi sau:

Too many tables. MySQL can only use 61 tables in a join.

Tôi nghĩ giới hạn cho MySql 4 là 31 bảng.

Một lời khuyên nếu bạn dự định sử dụng nhiều bảng trong truy vấn thì đã đến lúc bắt đầu suy nghĩ về việc đơn giản hóa thiết kế truy vấn của bạn.

+0

+1 để biết thông tin về giới hạn (cảm ơn). Tôi nghĩ rằng thông tin đặt điều này vào quan điểm đối với tôi, 8 của tôi tham gia trong số 61 khả năng có thể không tệ chút nào. – Ozzy

2

Tôi cũng đang tìm kiếm điều này và sau đó tôi tìm thấy giải pháp khác này, thêm "AND" như một phần của JOIN.

INNER JOIN kopplaMedlemIntresse 
ON intressen.id = kopplaMedlemIntresse.intresse_id AND kopplaMedlemIntresse.medlem_id = 3 
Các vấn đề liên quan