Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

Làm cách nào để tối ưu hóa truy vấn nếu bảng chứa 10000 mục nhập bằng MySQL?

Tôi sẽ cố gắng đơn giản hóa điều này HOÀN TOÀN bằng cách đặt trình kích hoạt trên các bảng khác của bạn và chỉ cần thêm một vài cột vào bảng User_Fans của bạn ... Một cột cho mỗi số lượng tương ứng () mà bạn đang cố gắng lấy ... từ Bài đăng, Người đăng bài, Bài bình luận, PostCommentLikes.

Khi một bản ghi được thêm vào bất kỳ bảng nào, chỉ cần cập nhật bảng user_fans của bạn để thêm 1 vào số lượng ... nó sẽ gần như ngay lập tức dựa trên ID khóa của người dùng. Đối với "LIKES" ... Tương tự, chỉ với điều kiện là thứ gì đó được kích hoạt dưới dạng "Thích", hãy thêm 1 .. Sau đó, truy vấn của bạn sẽ là một phép toán trực tiếp trên một bản ghi duy nhất và không dựa vào BẤT KỲ liên kết nào để tính toán một tổng giá trị "có trọng số". Khi bảng của bạn thậm chí còn lớn hơn, các truy vấn cũng sẽ dài hơn vì chúng có nhiều dữ liệu hơn để chuyển qua và tổng hợp. Bạn đang xem qua MỌI bản ghi user_fan, về bản chất là truy vấn mọi bản ghi từ tất cả các bảng khác.

Tất cả những gì đang nói, giữ nguyên các bảng như bạn có, tôi sẽ cấu trúc lại như sau ...

SELECT 
      uf.user_name,
      uf.user_id,
      @pc := coalesce( PostSummary.PostCount, 000000 ) as PostCount,
      @pl := coalesce( PostLikes.LikesCount, 000000 ) as PostLikes,
      @cc := coalesce( CommentSummary.CommentsCount, 000000 ) as PostComments,
      @cl := coalesce( CommentLikes.LikesCount, 000000 ) as CommentLikes,
      @pc + @cc AS sum_post,
      @pl + @cl AS sum_like, 
      @pCalc := (@pc + @cc) * 10 AS post_cal,
      @lCalc := (@pl + @cl) * 5 AS like_cal,
      @pCalc + @lCalc AS `total`
   FROM
      ( select @pc := 0,
               @pl := 0,
               @cc := 0,
               @cl := 0,
               @pCalc := 0
               @lCalc := 0 ) sqlvars,
      user_fans uf
        LEFT JOIN ( select user_id, COUNT(*) as PostCount
                       from post
                       group by user_id ) as PostSummary
           ON uf.user_id = PostSummary.User_ID

        LEFT JOIN ( select user_id, COUNT(*) as LikesCount
                       from post_likes
                       group by user_id ) as PostLikes
           ON uf.user_id = PostLikes.User_ID

        LEFT JOIN ( select user_id, COUNT(*) as CommentsCount
                       from post_comment
                       group by user_id ) as CommentSummary
           ON uf.user_id = CommentSummary.User_ID

        LEFT JOIN ( select user_id, COUNT(*) as LikesCount
                       from post_comment_likes
                       group by user_id ) as CommentLikes
           ON uf.user_id = CommentLikes.User_ID

   ORDER BY 
      `total` DESC 
   LIMIT 20

My variables are abbreviated as 
"@pc" = PostCount
"@pl" = PostLikes
"@cc" = CommentCount
"@cl" = CommentLike
"@pCalc" = weighted calc of post and comment count * 10 weighted value
"@lCalc" = weighted calc of post and comment likes * 5 weighted value

LEFT JOIN cho các truy vấn trước chạy các truy vấn đó NGAY LẬP TỨC, sau đó toàn bộ nội dung được kết hợp thay vì được nhấn như một truy vấn phụ cho mọi bản ghi. Bằng cách sử dụng COALESCE (), nếu không có mục nào như vậy trong kết quả bảng LEFT JOINed, bạn sẽ không gặp phải các giá trị NULL làm rối tung calcs, vì vậy tôi đã đặt chúng thành 000000.

XÁC NHẬN CÂU HỎI CỦA BẠN

Bạn có thể có bất kỳ QUERY nào dưới dạng "AS AliasResult". "As" cũng có thể được sử dụng để đơn giản hóa bất kỳ tên bảng dài nào để dễ đọc hơn. Bí danh cũng có thể được sử dụng cùng một bảng nhưng là một bí danh khác để có được nội dung tương tự, nhưng cho mục đích khác nhau.

select
      MyAlias.SomeField
   from
      MySuperLongTableNameInDatabase MyAlias ...

select
      c.LastName,
      o.OrderAmount
   from
      customers c
         join orders o
            on c.customerID = o.customerID  ...

select
      PQ.SomeKey
   from
      ( select ST.SomeKey
           from SomeTable ST
           where ST.SomeDate between X and Y ) as PQ
         JOIN SomeOtherTable SOT
            on PQ.SomeKey = SOT.SomeKey ...

Bây giờ, truy vấn thứ ba ở trên không thực tế khi yêu cầu (truy vấn đầy đủ dẫn đến bí danh "PQ" đại diện cho "PreQuery"). Điều này có thể được thực hiện nếu bạn muốn giới hạn trước một tập hợp các điều kiện phức tạp khác và muốn một tập hợp nhỏ hơn TRƯỚC KHI thực hiện các phép nối bổ sung vào nhiều bảng khác để có tất cả các kết quả cuối cùng.

Vì "FROM" không PHẢI là một bảng thực tế, nhưng có thể là một truy vấn trong chính nó, bất kỳ vị trí nào khác được sử dụng trong truy vấn, nên nó phải biết cách tham chiếu tập kết quả truy vấn trước này.

Ngoài ra, khi truy vấn các trường, chúng cũng có thể là "Dưới dạng FinalColumnName" để đơn giản hóa kết quả đến nơi chúng cũng sẽ được sử dụng.

selectCONCAT (User.Salutation, User.LastName) dưới dạng CourtesyNamefrom ...

selectOrder.NonTaxable + Order.Taxable + (Order.Taxable * Order.SalesTaxRate) as OrderTotalWithTaxfrom ...

Tên columnName "Là" KHÔNG bắt buộc phải là một tổng hợp, nhưng thường được thấy theo cách đó.

Bây giờ, đối với các biến MySQL ... Nếu bạn đang thực hiện một thủ tục được lưu trữ, nhiều người sẽ khai báo trước khi chúng đặt các giá trị mặc định của họ trước phần còn lại của thủ tục. Bạn có thể thực hiện chúng trong dòng trong một truy vấn chỉ bằng cách đặt và cung cấp cho kết quả đó một tham chiếu "Bí danh". Khi thực hiện các biến này, vùng chọn sẽ mô phỏng luôn trả về giá trị SINGLE RECORD của các giá trị. Nó gần giống như một bản ghi duy nhất có thể cập nhật được sử dụng trong truy vấn. Bạn không cần phải áp dụng bất kỳ điều kiện "Tham gia" cụ thể nào vì nó có thể không có bất kỳ ảnh hưởng nào đến phần còn lại của các bảng trong một truy vấn ... Về bản chất, tạo ra một kết quả Descartes, nhưng một bản ghi so với bất kỳ bảng nào khác sẽ không bao giờ tạo trùng lặp bằng mọi cách, vì vậy không có thiệt hại nào về phía hạ lưu.

select 
       ...
   from 
      ( select @SomeVar := 0,
               @SomeDate := curdate(),
               @SomeString := "hello" ) as SQLVars

Bây giờ, sqlvars hoạt động như thế nào. Hãy nghĩ về một chương trình tuyến tính ... Một lệnh được thực hiện theo trình tự chính xác khi truy vấn chạy. Giá trị đó sau đó được lưu trữ lại trong bản ghi "SQLVars" sẵn sàng cho lần tiếp theo. Tuy nhiên, bạn không tham chiếu nó là SQLVars.SomeVar hoặc SQLVars.SomeDate ... mà chỉ là @SomeVar:=someNewValue. Bây giờ, khi @var được sử dụng trong một truy vấn, nó cũng được lưu trữ dưới dạng "As ColumnName" trong tập kết quả. Đôi khi, đây có thể chỉ là một giá trị được tính toán cho người giữ chỗ để chuẩn bị cho bản ghi tiếp theo. Mỗi giá trị sau đó có sẵn trực tiếp cho hàng tiếp theo. Vì vậy, với mẫu sau ...

select
      @SomeVar := SomeVar * 2 as FirstVal,
      @SomeVar := SomeVar * 2 as SecondVal,
      @SomeVar := SomeVar * 2 as ThirdVal
   from
      ( select @SomeVar := 1 ) sqlvars,
      AnotherTable
   limit 3

Will result in 3 records with the values of 

FirstVal    SecondVal   ThirdVal
2           4           8
16          32          64
128         256         512

Lưu ý giá trị của @SomeVar được sử dụng như thế nào khi mỗi cột sử dụng nó ... Vì vậy, ngay cả trên cùng một bản ghi, giá trị được cập nhật sẽ ngay lập tức có sẵn cho cột tiếp theo ... Điều đó nói rằng, bây giờ hãy xem cách cố gắng tạo bản ghi mô phỏng / xếp hạng trên mỗi khách hàng ...

select
      o.CustomerID,
      o.OrderID
      @SeqNo := if( @LastID = o.CustomerID, @SeqNo +1, 1 ) as CustomerSequence,
      @LastID := o.CustomerID as PlaceHolderToSaveForNextRecordCompare
   from
      orders o,
      ( select @SeqNo := 0, @LastID := 0 ) sqlvars
   order by
      o.CustomerID

Mệnh đề "Order By" buộc các kết quả phải được trả về theo trình tự trước tiên. Vì vậy, ở đây, các bản ghi cho mỗi khách hàng được trả lại. Lần đầu tiên, LastID là 0 và ID khách hàng được cho là ... 5. Vì khác nhau, nó trả về 1 dưới dạng @SeqNo, THÌ nó bảo toàn ID khách hàng đó vào trường @LastID cho bản ghi tiếp theo. Bây giờ, bản ghi tiếp theo cho khách hàng ... ID cuối cùng giống nhau, vì vậy nó lấy @SeqNo (bây giờ =1), và thêm 1 thành 1 và trở thành số 2 cho cùng một khách hàng ... Tiếp tục trên đường dẫn .. .

Để trở nên tốt hơn trong việc viết các truy vấn, hãy xem thẻ MySQL và xem xét một số thành phần đóng góp lớn. Xem xét các câu hỏi và một số câu trả lời phức tạp và cách giải quyết vấn đề hoạt động. Không có nghĩa là không có những người khác có điểm danh tiếng thấp hơn chỉ mới bắt đầu và hoàn toàn có năng lực, nhưng bạn sẽ tìm thấy ai đưa ra câu trả lời tốt và lý do tại sao. Nhìn vào lịch sử các câu trả lời đã đăng của họ. Bạn càng đọc và làm theo nhiều, bạn càng xử lý tốt hơn khi viết các truy vấn phức tạp hơn.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cách kiểm tra Ci đã chèn dữ liệu thành công hay chưa

  2. Nhập các tệp SQL lớn hơn vào MySQL

  3. Tạo một ứng dụng Ruby on Rails mới bằng MySQL thay vì SQLite

  4. php kết nối cơ sở dữ liệu singleton, mã này có thực tiễn không?

  5. Ví dụ về DATE_SUB () - MySQL