2009-01-14 37 views
7

Tôi đang xem xét lưu trữ một số dữ liệu JMX từ các JVM trên nhiều máy chủ trong khoảng 90 ngày. Dữ liệu này sẽ là số liệu thống kê như kích thước heap và số lượng chuỗi. Điều này có nghĩa là một trong các bảng sẽ có khoảng 388 triệu bản ghi.Một số kỹ thuật tối ưu hóa cho bảng MySQL với hơn 300 triệu bản ghi là gì?

Từ dữ liệu này tôi đang xây dựng một số biểu đồ để bạn có thể so sánh số liệu thống kê được lấy từ Mbeans. Điều này có nghĩa là tôi sẽ lấy một số dữ liệu tại một khoảng thời gian bằng cách sử dụng dấu thời gian.

Vì vậy, câu hỏi thực sự là, Có anyway để tối ưu hóa bảng hoặc truy vấn để bạn có thể thực hiện các truy vấn này trong một khoảng thời gian hợp lý không?

Cảm ơn,

Josh

Trả lời

9

Có một vài điều bạn có thể làm:

  1. Xây dựng chỉ số của bạn để phù hợp với yêu cầu của bạn đang chạy. Chạy EXPLAIN để xem các loại truy vấn được chạy và đảm bảo rằng tất cả các truy vấn đều sử dụng chỉ mục nếu có thể.

  2. Phân vùng bảng của bạn. Paritioning là một kỹ thuật để tách một bảng lớn thành nhiều cái nhỏ hơn bằng một khóa (tổng hợp) cụ thể. MySQL hỗ trợ nội bộ này từ ver. 5.1.

  3. Nếu cần, hãy tạo bảng tóm tắt để lưu vào bộ phận truy vấn của bạn. Sau đó chạy truy vấn của bạn dựa vào bảng tóm tắt. Tương tự, các bảng trong bộ nhớ tạm thời có thể được sử dụng để lưu trữ chế độ xem đơn giản của bảng của bạn dưới dạng giai đoạn tiền xử lý.

2

3 gợi ý:

  1. index
  2. index
  3. index

tái bút: đối với dấu thời gian bạn có thể gặp phải các vấn đề hiệu suất - tùy thuộc vào cách MySQL xử lý DATETIME và TIMESTAMP nội bộ, có thể tốt hơn để lưu dấu thời gian dưới dạng số nguyên. (# secs từ 1970 hoặc bất cứ điều gì)

2

Vâng, để bắt đầu, tôi khuyên bạn nên sử dụng chế độ "ngoại tuyến" để tạo dữ liệu 'sẵn sàng biểu đồ' (cho hầu hết các trường hợp thông thường) thay vì cố truy vấn dữ liệu thô theo yêu cầu.

1

Nếu bạn đang sử dụng MYSQL 5.1, bạn có thể sử dụng các tính năng mới. nhưng được cảnh báo rằng chúng chứa nhiều lỗi.

trước tiên bạn nên sử dụng các chỉ mục. nếu điều này là không đủ, bạn có thể cố gắng phân chia các bảng bằng cách sử dụng phân vùng.

nếu điều này cũng không hoạt động, bạn cũng có thể thử cân bằng tải.

1

Một vài đề xuất.Bạn có thể sẽ chạy các truy vấn tổng hợp về nội dung này, vì vậy sau (hoặc trong khi) bạn tải dữ liệu vào các bảng của mình, bạn nên tổng hợp trước dữ liệu, ví dụ như tổng số tính toán trước theo giờ hoặc theo người dùng, hoặc theo tuần, bất cứ điều gì, bạn có ý tưởng và lưu trữ nó trong các bảng bộ nhớ cache mà bạn sử dụng cho các biểu đồ báo cáo của mình. Nếu bạn có thể thu thập số liệu của mình theo thứ tự độ lớn thì tốt cho bạn!

Điều này có nghĩa là tôi sẽ lấy một số dữ liệu tại một khoảng thời gian bằng dấu thời gian.

Vì vậy, điều này có nghĩa là bạn chỉ sử dụng dữ liệu từ X ngày qua?

Xóa dữ liệu cũ khỏi bảng có thể chậm một cách khủng khiếp nếu bạn có vài chục triệu hàng để xóa, phân vùng rất tốt cho điều đó (chỉ cần thả phân vùng cũ). Nó cũng nhóm tất cả các bản ghi từ cùng một khoảng thời gian gần nhau trên đĩa sao cho nó hiệu quả hơn nhiều bộ nhớ cache.

Bây giờ nếu bạn sử dụng MySQL, tôi khuyên bạn nên sử dụng các bảng MyISAM. Bạn không nhận được sự chống va chạm hoặc giao dịch và khóa là câm, nhưng kích thước của bảng nhỏ hơn nhiều so với InnoDB, có nghĩa là nó có thể phù hợp với RAM, có nghĩa là truy cập nhanh hơn nhiều.

Vì các tập hợp lớn có thể liên quan đến rất nhiều IO đĩa tuần tự, một hệ thống IO nhanh như RAID10 (hoặc SSD) là một điểm cộng.

Có cách nào để tối ưu hóa bảng hoặc truy vấn để bạn có thể thực hiện các truy vấn này trong một khoảng thời gian hợp lý không?

Điều đó phụ thuộc vào bảng và truy vấn; không thể đưa ra lời khuyên nào mà không biết thêm.

Nếu bạn cần truy vấn báo cáo phức tạp với các tập hợp lớn và tham gia, hãy nhớ rằng MySQL không hỗ trợ bất kỳ JOINs ưa thích, hoặc hash-aggregates, hoặc bất cứ điều gì khác hữu ích thực sự, về cơ bản điều duy nhất nó có thể làm là là tốt trên một bảng lưu trữ, và hoàn toàn tàn bạo trên các trường hợp khác nếu một số truy cập ngẫu nhiên có liên quan.

Tôi đề nghị bạn nên kiểm tra với Postgres. Đối với tập hợp lớn, trình tối ưu hóa thông minh hơn hoạt động tốt.

Ví dụ:

CREATE TABLE t (id INTEGER PRIMARY KEY AUTO_INCREMENT, category INT NOT NULL, counter INT NOT NULL) ENGINE=MyISAM; 
INSERT INTO t (category, counter) SELECT n%10, n&255 FROM serie; 

(serie chứa đường 16M với n = 1 .. 16000000)

MySQL Postgres  
58 s  100s  INSERT 
75s  51s  CREATE INDEX on (category,id) (useless) 
9.3s  5s   SELECT category, sum(counter) FROM t GROUP BY category; 
1.7s  0.5s  SELECT category, sum(counter) FROM t WHERE id>15000000 GROUP BY category; 

Trên một truy vấn đơn giản như pg đây là khoảng 2-3x nhanh hơn (chênh lệch sẽ lớn hơn nhiều nếu tham gia phức tạp có liên quan).

0
  1. GIẢI THÍCH CHỌN bạn Queries
  2. LIMIT 1 Khi Bắt một Unique Row SELECT * FROM dùng ĐÂU state = 'Alabama' // sai SELECT 1 TỪ ĐÂU dùng state = LIMIT 'Alabama' 1

  3. Lập chỉ mục các trường tìm kiếm Chỉ mục không chỉ dành cho các khóa chính hoặc các khóa duy nhất. Nếu có bất kỳ cột nào trong bảng của bạn mà bạn sẽ tìm kiếm, bạn hầu như luôn luôn lập chỉ mục chúng.

  4. Chỉ mục và sử dụng các loại cột tương tự cho tham gia Nếu ứng dụng của bạn chứa nhiều truy vấn JOIN, bạn cần đảm bảo rằng các cột bạn tham gia được lập chỉ mục trên cả hai bảng. Điều này ảnh hưởng đến cách MySQL tối ưu hóa nội bộ hoạt động nối.

  5. KHÔNG TRÌNH TỰ DO RAND() Nếu bạn thực sự cần hàng ngẫu nhiên trong kết quả của mình, có nhiều cách tốt hơn để thực hiện. Cấp nó có mã bổ sung, nhưng bạn sẽ ngăn chặn một nút cổ chai mà được cấp số nhân tồi tệ hơn khi dữ liệu của bạn phát triển. Vấn đề là, MySQL sẽ phải thực hiện RAND() hoạt động (có sức mạnh xử lý) cho mỗi hàng trong bảng trước khi sắp xếp nó và cho bạn chỉ 1 hàng.

  6. Sử dụng ENUM trên VARCHAR Cột loại ENUM rất nhanh và nhỏ gọn. Nội bộ chúng được lưu trữ như TINYINT, nhưng chúng có thể chứa và hiển thị các giá trị chuỗi.

  7. Sử dụng NOT NULL Nếu bạn có thể Trừ khi bạn có lý do rất cụ thể để sử dụng giá trị NULL, bạn nên luôn đặt cột là NOT NULL.

    "Cột NULL yêu cầu không gian bổ sung trong hàng để ghi lại giá trị của chúng là NULL. Đối với bảng MyISAM, mỗi cột NULL mất thêm một bit, được làm tròn lên byte gần nhất."

  8. Lưu địa chỉ IP dưới dạng UNSIGNED INT Trong truy vấn của bạn, bạn có thể sử dụng INET_ATON() để chuyển đổi và IP thành số nguyên và INET_NTOA() cho ngược lại. Cũng có các hàm tương tự trong PHP được gọi là ip2long() và long2ip().

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