Chọn truy vấn mất nhiều thời gian hơn nó nên


9

Tôi có một bảng cơ sở dữ liệu MySQL với gần 23 triệu bản ghi. Bảng này không có khóa chính, vì không có gì là duy nhất. Nó có 2 cột, cả hai đều được lập chỉ mục. Dưới đây là cấu trúc của nó:

nhập mô tả hình ảnh ở đây

Dưới đây là một số dữ liệu của nó:

nhập mô tả hình ảnh ở đây

Bây giờ, tôi đã chạy một truy vấn đơn giản:

SELECT `indexVal` FROM `key_word` WHERE `hashed_word`='001'

Thật không may, điều này mất hơn 5 giây để lấy dữ liệu và hiển thị chúng cho tôi. Bảng tương lai của tôi sẽ có 150 tỷ hồ sơ, vì vậy thời gian này là rất rất cao.

Tôi chạy Explainlệnh để xem những gì đang xảy ra. Kết quả là dưới đây.

nhập mô tả hình ảnh ở đây

Sau đó, tôi chạy hồ sơ bằng cách sử dụng lệnh dưới đây.

SET profiling=1;
SELECT `indexVal` FROM `key_word` WHERE `hashed_word` = '001';
SHOW profile;

Dưới đây là kết quả của hồ sơ:

nhập mô tả hình ảnh ở đây

Dưới đây là một số thông tin về bảng của tôi:

nhập mô tả hình ảnh ở đây

Vì vậy, tại sao điều này là quá lâu? Họ được lập chỉ mục quá! Trong tương lai, tôi phải chạy rất nhiều LIKElệnh, vì vậy việc này mất quá nhiều thời gian. Điều gì đã đi sai?


"Bảng này không có khóa chính, vì không có gì là duy nhất." Vâng, đúng ... Thời gian để kiểm tra lại thiết kế của bạn. Tất cả các bảng phải có khóa chính (hoặc duy nhất).
ypercubeᵀᴹ

Câu trả lời:


10

Bạn hỏi " tại sao việc này mất quá nhiều thời gian ?". Bạn cũng nói " Thật không may, việc này mất hơn 5 giây để lấy dữ liệu và hiển thị chúng cho tôi ". Ngoài ra, bạn đã báo cáo đầu ra hồ sơ của truy vấn của bạn.

Như bạn có thể thấy chính mình, tổng số lần được trình hồ sơ báo cáo cho mỗi bước được tính là 0,000154 giây. Vì vậy, từ quan điểm của trình hồ sơ, truy vấn đã được hoàn thành trong thời gian như vậy (0,000154).

Vậy tại sao bạn nhận được kết quả trong " ... hơn 5 giây? ".

Bạn nói rằng bạn đang lọc một bảng kỷ lục 23 triệu với trường 3 char. Thật không may, bạn không cho chúng tôi biết có bao nhiêu bản ghi truy vấn của bạn đang trả về ... nhưng nhờ có GIẢI THÍCH GIẢI THÍCH được cung cấp, có vẻ như truy vấn của bạn đã trả về 336052 bản ghi.

Dường như, tất cả hoạt động của bạn đều chạy qua một số GUI (PHPMyAdmin?).

Vì vậy, sau tất cả những điều trên, chúng tôi có thể định dạng lại câu hỏi ban đầu của bạn là:

"tại sao tôi nhận được, trong GUI của tôi, các bản ghi 336.052 được hiển thị trong hơn 5 giây, nếu thời gian thực hiện MySQL cho truy vấn có liên quan là 0,000154 giây?"

Câu trả lời, theo tôi, khá đơn giản: 5 giây là thời gian (thực sự rất thấp) để cho phép các bản ghi 336.052 đi dọc theo đường dẫn: MySQL engine => thư viện máy khách MySQL => mô-đun MySQL MySQL => Apache => Mạng = > ngăn xếp TCP / IP PC của bạn => Trình duyệt => Trình phân tích cú pháp / trình tạo DOM / v.v. => Trang HTML được kết xuất.

Đối với kinh nghiệm trước đây của tôi, thời gian cần thiết để truyền kết quả là "thông thường" cao hơn nhiều so với thời gian cần thiết để truy xuất dữ liệu đó. Điều này đặc biệt đúng khi các thư viện như PHP-MySQL hoặc Perl-DBD-MySQL có liên quan: chúng thực sự đòi hỏi nhiều thời gian để lấy lại các bản ghi, sau khi MySQL đã xác định đúng (... và trích xuất) tất cả chúng.

Làm thế nào để giải quyết vấn đề này?

Một lần nữa, khá dễ dàng: bạn có thực sự chắc chắn rằng bạn cần TẤT CẢ bản ghi 336.052, trong một tập dữ liệu duy nhất, toàn bộ không?

  • Nếu câu trả lời của bạn thực sự là "CÓ! Tôi cần tất cả trong số họ", thì ứng dụng của bạn sẽ tự xử lý PAGINATION và / hoặc NGƯỜI DÙNG tương tác và ... một khi đã thu thập được tất cả dữ liệu đó, có lẽ nó sẽ tốn rất nhiều thời gian tương tác với người dùng mà không yêu cầu bất kỳ tương tác MySQL nào nữa. Trong trường hợp như vậy, chờ trong 5 giây (hoặc thậm chí nhiều hơn) không phải là vấn đề;

  • Nếu câu trả lời của bạn là "KHÔNG, tôi muốn xử lý kích thước tập dữ liệu" con người "nhiều hơn, hơn là bạn phải tinh chỉnh truy vấn của mình (ít nhất) để nó sẽ trả lại cho bạn bộ dữ liệu" người "hơn (hàng chục hoặc, hàng trăm, nhiều nhất, hồ sơ). Trong trường hợp như vậy, tôi cá rằng bạn sẽ nhận được kết quả của mình trong thời gian ngắn hơn.


BTW: đây chính xác là cùng một vấn đề bạn gặp phải trong bài đăng khác này , tại ServerFault: 88 giây để cho 132M bản ghi di chuyển dọc theo con đường ma thuật .... không liên quan đến mysql :-)


Tôi đang mong đợi một câu trả lời từ op.
J Namaranjan

5
  1. Kiểm tra mysql innodb_buffer_pool_size . Nó phải đủ lớn - càng nhiều, càng tốt. Nhưng không nhiều để tránh hoán đổi hệ điều hành.

    show variables like 'innodb_buffer_pool_size'

    sẽ hiển thị kích thước bộ đệm theo byte.

  2. Kiểm tra truy vấn nhiều lần. Lần chạy đầu tiên có thể quá dài vì dữ liệu sẽ được đọc từ đĩa vào bộ nhớ. Khi bạn đang chạy truy vấn lần đầu tiên, dữ liệu vẫn không nằm trong bộ đệm innodb và phải được đọc từ đĩa. Đó là chậm hơn nhiều so với nếu dữ liệu sẽ có trong bộ đệm. Vì vậy, hãy chạy truy vấn một vài lần để đảm bảo nó được phục vụ từ bộ đệm.

  3. Vô hiệu hóa bộ đệm truy vấn vì mỗi lần chạy hệ quả sẽ được thực hiện từ nó và sẽ làm sai lệch kết quả kiểm tra. Có một cơ chế trong MySQL, được gọi là "bộ đệm truy vấn" được thiết kế để lưu trữ các truy vấn cùng với kết quả của chúng. Vì vậy, lần thứ hai MySQL được yêu cầu chạy truy vấn, nó có thể bỏ qua việc thực thi và lấy kết quả từ bộ đệm truy vấn.

  4. Xem xét sử dụng "chỉ số bao phủ":

    ALTER TABLE key_word ADD KEY IX_hashed_word_indexVal (hashed_word, indexVal);

Điều này sẽ hiệu quả hơn nhiều, kể từ đó MySQL có thể thực hiện yêu cầu truy vấn từ chỉ mục.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.