2009-10-07 35 views
47

Tôi có ba bảng để xác định người sử dụng:số MySQL các mặt hàng trong vòng "tại khoản"

USER: user_id (int), username (varchar) 
USER_METADATA_FIELD: user_metadata_field_id (int), field_name (varchar) 
USER_METADATA: user_metadata_field_id (int), user_id (int), field_value (varchar) 

Tôi muốn tạo một người dùng lớp giữa có quyền truy cập nhất định để những người dùng khác trong ứng dụng. Để xác định người sử dụng đăng nhập sử dụng có thể truy cập, tôi đang sử dụng một subquery như sau:

SELECT user_id FROM user WHERE user_id 
    IN (SELECT user_id 
     FROM user_metadata 
     WHERE user_metadata_field_id = 1 AND field_value = 'foo') 

Hiện nay tôi đang giữ chuỗi subquery trong một biến và sau đó tự động chèn nó vào truy vấn bên ngoài mỗi khi tôi cần để kéo danh sách người dùng. Sau khi làm điều này tôi nghĩ, "nó đã được tốt hơn để chỉ lưu trữ một chuỗi các thực tế user_id s".

Vì vậy, thay vì lưu trữ này trong một biến ...

$subSql = "SELECT user_id FROM user_metadata WHERE user_metadata_field_id = 1 AND field_value = 'foo'"; 

... Tôi thực sự thực hiện các truy vấn và lưu trữ các kết quả như thế này ...

$subSql = "12, 56, 89, 100, 1234, 890"; 

Sau đó, khi tôi cần để thu hút người dùng mà người dùng đã đăng nhập có quyền truy cập vào, tôi có thể làm như vậy với:

$sql = "SELECT user_id FROM user WHERE user_id IN ($subSql)"; 

Và cuối cùng là các câu hỏi:

Bạn có thể sử dụng bao nhiêu mục trong MySQL IN CLAUSE? Việc lưu trữ các id thực tế thay vì câu lệnh sub-sql phải nhanh hơn để thực hiện truy vấn bên ngoài đó mỗi lần, đúng không?

Trả lời

33

Bắt đầu từ một số nhất định, các bảng IN sẽ nhanh hơn.

MySQL có nội dung bên trong mã giúp tạo phạm vi trên một số lượng lớn các giá trị không đổi chậm hơn so với thực hiện tương tự trong vòng lặp lồng nhau.

Xem bài viết này trong blog của tôi để biết chi tiết thực hiện:

+0

Hey Quassnoi: có vẻ như có rất nhiều bất đồng về kiểm tra hiệu suất của bạn và xác nhận của bạn rằng một bảng tạm thời là tốt hơn. Tôi nghĩ rằng bạn có thể sai ở đây. – IcedDante

+1

@IcedDante: có các kịch bản để tái tạo mọi thứ tôi đã viết trong bài đăng trên blog. Bạn được tự do viết bài đăng blog của riêng bạn, với các kịch bản của riêng bạn, và chứng minh tôi sai như thế nào. Nếu không, các cuộc đàm phán như thế này chỉ là không khí nóng. – Quassnoi

+0

Tôi biết câu hỏi này là cũ, nhưng câu trả lời của bạn đã không trả lời câu hỏi thực: "Bạn có thể sử dụng bao nhiêu mục trong MySQL IN CLAUSE?" – Gusman

9

Như lời đề nghị để đáp ứng Quassnoi, người ta tình cờ khi cân nhắc thực tế khác, trước nhấn bất kỳ giới hạn có thể áp bằng cách thực hiện phiên bản MySql nhất định (*). Do đó, vì số lượng người dùng quản trị (hoặc các tiêu chí khác có thể yêu cầu xây dựng IN) phát triển, nên tìm cách sử dụng các lựa chọn thay thế cho chữ "IN", chẳng hạn như việc sử dụng các bảng tạm thời (hoặc thậm chí là vĩnh viễn).

Vì bạn đang xem xét xử lý đặc biệt tiêu chí "người dùng quản trị", vì mục đích hiệu suất, tôi muốn đưa ra nhận xét và đề xuất.

Nhận xét: Đây có phải là trường hợp tối ưu hóa sớm không?
Tôi không biết các chi tiết cụ thể của cơ sở dữ liệu này, khối lượng, độ phức tạp, v.v. Và, có, tôi biết về một số cống hiệu suất được trả cho định dạng EAV (Entity-Attribute-Value), nhưng tôi nghĩ rằng ngay cả đối với các doanh nghiệp thành công, cơ sở dữ liệu tài khoản hiếm khi vượt quá 10.000 người dùng.Vì vậy, ngay cả với rất nhiều thuộc tính cho mỗi người dùng, chúng tôi vẫn đang xem xét một bảng EAV tương đối nhỏ, có thể không yêu cầu loại tối ưu hóa này. (Mặt khác, một số thủ thuật tối ưu hóa khác có thể được chào đón ở các khu vực khác).
Hơn nữa, các trường hợp sử dụng điển hình, liên quan đến một số yêu cầu tương đối vào cơ sở dữ liệu tài khoản, liên quan đến các truy vấn khác, và đây là lý do khác để tránh mọi xem xét hiệu suất không quan trọng đối với các tính năng liên quan đến tài khoản của ứng dụng.

Góp ý: Có lẽ sử dụng "lại bình thường thuộc tính"
Đối với thuộc tính được singled có giá trị, và đặc biệt nếu họ đang ngắn, họ có thể được di chuyển (hoặc trùng lặp) trong bảng Entity ('USER' trong trường hợp này). Điều này giới thiệu một chút logic tại các mục thời gian được chèn vào hoặc cập nhật, nhưng điều này dẫn đến nhiều kết nối (hoặc truy vấn con) và cũng cung cấp cơ hội để xem xét các chỉ mục đa trường để hỗ trợ các trường hợp sử dụng phổ biến nhất.

(*) Có bị giới hạn không?
Tôi chưa đọc về bất kỳ giới hạn nào như vậy; Tôi biết Oracle đã có (có) một giới hạn 1.000 tại một thời gian, MSSQL không; tất nhiên tất cả các máy chủ đều có một giới hạn dựa trên tổng chiều dài của câu lệnh SQL, nhưng đây là một con số thực sự lớn! nếu một người từng vấp phải cái đó, anh ta/cô ấy có những vấn đề khác ... ;-)

4

Chính điều khoản IN của chính nó không có giới hạn như vậy. Tôi đã thử với 8000 yếu tố làm việc tốt cho tôi. Ngăn xếp lỗi tràn bộ nhớ có thể là biến khai báo,

117

Từ manual:

Số các giá trị trong danh sách IN chỉ bị giới hạn bởi giá trị max_allowed_packet.

+10

Ví dụ về cài đặt mặc định là 'max_allowed_packet | 1048576' (1 MB) – icvg

+7

+1 để trả lời câu hỏi. Cảm ơn bạn. – Bryan

+1

[Giá trị mặc định của max_allowed_packet là 4MB] (http://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_max_allowed_packet) –

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