2009-02-08 37 views
5

Tôi muốn bắt đầu đếm số lần trang web được xem và do đó cần một số loại bộ đếm đơn giản. Phương pháp mở rộng tốt nhất để làm điều này là gì?Cách tốt nhất để thực hiện một trường truy cập trong MySQL

Giả sử tôi có một Frobs bàn nơi mỗi hàng tương ứng với một trang - một số tùy chọn hiển nhiên là:

  1. Có một int NumViews unsigned lĩnh vực trong bảng Frobs mà được được cập nhật theo từng xem sử dụng UPDATE Frobs SET NumViews = NumViews + 1 . Đơn giản nhưng không tốt ở quy mô lớn như tôi hiểu.

  2. Có bảng riêng FrobViews trong đó hàng mới được chèn cho mỗi chế độ xem. Để hiển thị số lượt xem , bạn cần phải thực hiện một đơn giản SELECT COUNT(*) AS NumViews FROM FrobViews WHERE FrobId = '%d' GROUP BY FrobId. Điều này không liên quan đến bất kỳ cập nhật nào để tránh việc khóa bảng trong các bảng MyISAM - tuy nhiên, hiệu suất đọc sẽ bị ảnh hưởng nếu bạn muốn hiển thị số lượt xem trên mỗi trang.

Bạn làm như thế nào?

Có một số lời khuyên hay ở đây: http://www.mysqlperformanceblog.com/2007/07/01/implementing-efficient-counters-with-mysql/ nhưng tôi muốn nghe quan điểm của cộng đồng SO.

Tôi đang sử dụng InnoDb vào lúc này, nhưng tôi quan tâm đến câu trả lời cho cả InnoDb và MyISAM.

Trả lời

2

Tôi sẽ tiếp cận phương pháp thứ hai của bạn và tổng hợp dữ liệu vào bảng từ giải pháp đầu tiên của bạn trên cơ sở thường xuyên. Bằng cách này, bạn sẽ có được những ưu điểm của cả hai giải pháp. Để rõ ràng hơn: Trên mỗi lần truy cập, bạn chèn một hàng vào một bảng (cho phép đặt tên là hit_counters). Bảng này chỉ có một trường (pageid). Mỗi x giây bạn chạy một kịch bản (thông qua một cronjob) mà tổng hợp dữ liệu từ bảng hit_counters và đặt nó vào một bảng thứ hai (cho phép đặt tên là 'hits'. Có hai trường: pageid và tổng số lần truy cập.

Tôi không chắc chắn nhưng imho có innodb không giúp bạn rất nhiều cho giải pháp 1 nếu bạn nhận được nhiều lượt truy cập trên cùng một trang: Innodb khóa hàng trong khi cập nhật để tất cả các bản cập nhật khác cho hàng này sẽ bị trì hoãn

Tùy thuộc vào chương trình của bạn được viết bằng cách nào bạn cũng có thể cập nhật các bản cập nhật với nhau bằng cách đếm trong ứng dụng của bạn và cập nhật cơ sở dữ liệu chỉ sau mỗi giây.Điều này sẽ chỉ hoạt động nếu bạn sử dụng ngôn ngữ lập trình mà bạn có lưu trữ liên tục (như Java Servlets chứ không phải PHP)

3

Nếu khả năng mở rộng quan trọng hơn đối với bạn so với độ chính xác tuyệt đối của các số liệu thì bạn có thể cache số lượt xem trong ứng dụng trong một thời gian ngắn thay vì nhấn cơ sở dữ liệu trên mỗi lần xem trang - ví dụ, chỉ cập nhật cơ sở dữ liệu một lần mỗi 100 lượt xem .

Nếu ứng dụng của bạn bị treo giữa các cập nhật cơ sở dữ liệu thì rõ ràng bạn sẽ mất một số dữ liệu, nhưng nếu bạn có thể chịu đựng một số lượng không chính xác thì đây có thể là một cách tiếp cận hữu ích.

0

Những gì tôi làm và có thể không áp dụng cho kịch bản của bạn, đang trong thủ tục lưu trữ chuẩn bị/trả về dữ liệu được hiển thị trên trang, tôi thực hiện cập nhật bộ đếm bảng cùng một lúc để trả về dữ liệu - theo cách đó, chỉ có một cuộc gọi đến máy chủ nhận cả dữ liệu và cập nhật bộ đếm trong cùng một cuộc gọi.

Nếu bạn không sử dụng SP, (hoặc nếu không có dữ liệu cơ sở dữ liệu trên trang của bạn), tùy chọn này có thể không có sẵn cho bạn, nhưng nếu bạn là một thứ gì đó cần xem xét.

3

Chèn vào Cơ sở dữ liệu không phải là thứ bạn muốn thực hiện trên lượt xem trang. Bạn có thể gặp phải các vấn đề với việc cập nhật cơ sở dữ liệu nô lệ của bạn với tất cả các chèn kể từ khi sao chép đơn luồng trên MySQL.

Tại công ty của tôi, chúng tôi phục vụ 25 triệu lần xem trang mỗi ngày và chúng tôi đã thực hiện một phương pháp tiếp cận theo từng cấp.

Bộ đếm lượt xem được lưu trữ trong một bảng riêng biệt với 2 cột (profileId, viewCounter) đều là số nguyên không dấu.

Đối với các mục không thường xuyên được xem, chúng tôi cập nhật bảng trên lượt xem trang. Đối với các mục được xem thường xuyên, chúng tôi cập nhật MySQL khoảng 1/10 thời gian. Đối với cả hai loại, chúng tôi cập nhật Memcache trên mỗi lần truy cập.
int Memcache::increment (string $key [, int $value = 1 ])

if (pageViews < 10000) { UPDATE page_view SET viewCounter=viewCounter+1 WHERE profileId = :? }

else if ((int)rand(10) == 1) { //UPDATE page_view SET viewCounter= ?:cache_value WHERE profileId = :? }

làm count (*) là rất không hiệu quả trong InnoDB (MyISAM giữ đếm số liệu thống kê trong chỉ mục), nhưng MyISAM sẽ khóa bàn về đọc giảm đồng thời. việc đếm() cho 50.000 hoặc 100.000 hàng sẽ mất nhiều thời gian. Việc chọn một PK sẽ rất nhanh.

Nếu bạn cần thêm khả năng mở rộng, bạn có thể muốn xem redis

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