2009-12-29 36 views
6

EDIT:Quy trình lưu trữ MySQL gây ra sự cố?

tôi đã thu hẹp thời gian chờ đợi mysql của tôi xuống đến dòng này:

IF @resultsFound > 0 THEN 
     INSERT INTO product_search_query (QueryText, CategoryId) VALUES (keywords, topLevelCategoryId); 
    END IF; 

Bất cứ ý tưởng tại sao điều này sẽ gây ra một vấn đề? Tôi không thể làm việc được! Xin chào các bạn, tôi đã viết một proc được lưu trữ để tìm kiếm các sản phẩm trong một số danh mục nhất định, do một số ràng buộc nhất định, tôi không thể làm những gì tôi muốn (giới hạn, nhưng vẫn trả về tổng số hàng). được tìm thấy, với phân loại, vv ..)

Điều này có nghĩa là chia nhỏ một chuỗi các Id danh mục, từ 1,2,3 thành bảng tạm thời, sau đó tạo truy vấn tìm kiếm toàn văn dựa trên tùy chọn sắp xếp và giới hạn, thực hiện chuỗi truy vấn và sau đó chọn ra tổng số kết quả.

Bây giờ, tôi biết tôi không có guru MySQL, rất xa nó, tôi đã có nó làm việc, nhưng tôi tiếp tục nhận được thời gian với tìm kiếm sản phẩm vv .. vì vậy tôi nghĩ rằng điều này có thể gây ra một số loại vấn đề?

Có ai có ý tưởng nào về cách tôi có thể dọn dẹp hoặc thậm chí làm theo cách tốt hơn mà tôi có thể không biết?

Cảm ơn ..

DELIMITER $$ 

DROP PROCEDURE IF EXISTS `product_search` $$ 
CREATE DEFINER=`root`@`localhost` PROCEDURE `product_search`(keywords text, categories text, topLevelCategoryId int, sortOrder int, startOffset int, itemsToReturn int) 
BEGIN 

declare foundPos tinyint unsigned; 
declare tmpTxt text; 
declare delimLen tinyint unsigned; 
declare element text; 
declare resultingNum int unsigned; 

drop temporary table if exists categoryIds; 
create temporary table categoryIds 
(
`CategoryId` int 
) engine = memory; 


set tmpTxt = categories; 

set foundPos = instr(tmpTxt, ','); 
while foundPos <> 0 do 
set element = substring(tmpTxt, 1, foundPos-1); 
set tmpTxt = substring(tmpTxt, foundPos+1); 
set resultingNum = cast(trim(element) as unsigned); 

insert into categoryIds (`CategoryId`) values (resultingNum); 

set foundPos = instr(tmpTxt,','); 
end while; 

if tmpTxt <> '' then 
insert into categoryIds (`CategoryId`) values (tmpTxt); 
end if; 

CASE 
    WHEN sortOrder = 0 THEN 
    SET @sortString = "ProductResult_Relevance DESC"; 
    WHEN sortOrder = 1 THEN 
    SET @sortString = "ProductResult_Price ASC"; 
    WHEN sortOrder = 2 THEN 
    SET @sortString = "ProductResult_Price DESC"; 
    WHEN sortOrder = 3 THEN 
    SET @sortString = "ProductResult_StockStatus ASC"; 
END CASE; 

SET @theSelect = CONCAT(CONCAT(" 
    SELECT SQL_CALC_FOUND_ROWS 
     supplier.SupplierId as Supplier_SupplierId, 
     supplier.Name as Supplier_Name, 
     supplier.ImageName as Supplier_ImageName, 

     product_result.ProductId as ProductResult_ProductId, 
     product_result.SupplierId as ProductResult_SupplierId, 
     product_result.Name as ProductResult_Name, 
     product_result.Description as ProductResult_Description, 
     product_result.ThumbnailUrl as ProductResult_ThumbnailUrl, 
     product_result.Price as ProductResult_Price, 
     product_result.DeliveryPrice as ProductResult_DeliveryPrice, 
     product_result.StockStatus as ProductResult_StockStatus, 
     product_result.TrackUrl as ProductResult_TrackUrl, 
     product_result.LastUpdated as ProductResult_LastUpdated, 

     MATCH(product_result.Name) AGAINST(?) AS ProductResult_Relevance 
    FROM 
     product_latest_state product_result 
    JOIN 
     supplier ON product_result.SupplierId = supplier.SupplierId 
    JOIN 
     category_product ON product_result.ProductId = category_product.ProductId 
    WHERE 
     MATCH(product_result.Name) AGAINST (?) 
    AND 
     category_product.CategoryId IN (select CategoryId from categoryIds) 
    ORDER BY 
     ", @sortString), " 
    LIMIT ?, ?; 
    "); 

    set @keywords = keywords; 
    set @startOffset = startOffset; 
    set @itemsToReturn = itemsToReturn; 

    PREPARE TheSelect FROM @theSelect; 
    EXECUTE TheSelect USING @keywords, @keywords, @startOffset, @itemsToReturn; 

    SET @resultsFound = FOUND_ROWS(); 

    SELECT @resultsFound as 'TotalResults'; 

    IF @resultsFound > 0 THEN 
     INSERT INTO product_search_query (QueryText, CategoryId) VALUES (keywords, topLevelCategoryId); 
    END IF; 

END $$ 

DELIMITER ; 

Bất kỳ sự giúp đỡ rất rất nhiều đánh giá cao!

+1

Có thể nhận được một MÔ TẢ DESCRIBE cho các bảng được sử dụng trong này không? Tôi nghĩ chúng ta có thể làm giảm sự phức tạp và, có thể, cũng tăng tốc độ nếu tôi có thêm đôi mắt nữa. –

+0

Tôi nhận xét kevins thứ hai. quá ít để tiếp tục. – DeveloperChris

Trả lời

4

Có rất ít điều bạn có thể thực hiện với truy vấn này.

Hãy thử điều này:

  1. Tạo một PRIMARY KEY trên categoryIds (categoryId)

    • Hãy chắc chắn rằng supplier (supplied_id) là một PRIMARY KEY

    • Hãy chắc chắn rằng category_product (ProductID, CategoryID) (theo thứ tự này) là một PRIMARY KEY hoặc bạn có chỉ mục có số ProductID dẫn đầu.

Cập nhật:

Nếu đó là INSERT gây ra vấn đề và product_search_query trong một bảng MyISAM vấn đề này có thể được với MyISAM khóa.

MyISAM khóa toàn bộ bảng nếu nó quyết định chèn hàng vào một khối miễn phí ở giữa bảng có thể gây ra thời gian chờ.

Hãy thử sử dụng INSERT DELAYED thay vì:

IF @resultsFound > 0 THEN 
    INSERT DELAYED INTO product_search_query (QueryText, CategoryId) VALUES (keywords, topLevelCategoryId); 
END IF; 

Điều này sẽ đặt các hồ sơ vào hàng đợi chèn và trở về ngay lập tức. Bản ghi sẽ được thêm sau không đồng bộ.

Lưu ý rằng bạn có thể mất thông tin nếu máy chủ chết sau khi lệnh được đưa ra nhưng trước khi các bản ghi thực sự được chèn vào.

Cập nhật:

Từ bảng của bạn là InnoDB, nó có thể là một vấn đề với bảng khóa. INSERT DELAYED không được hỗ trợ trên InnoDB.

Tùy thuộc vào bản chất của truy vấn, các truy vấn DML trên InnoDB bảng có thể đặt các khóa khoảng cách sẽ khóa chèn.

Ví dụ:

CREATE TABLE t_lock (id INT NOT NULL PRIMARY KEY, val INT NOT NULL) ENGINE=InnoDB; 
INSERT 
INTO t_lock 
VALUES 
     (1, 1), 
     (2, 2); 

truy vấn này thực hiện ref quét và đặt ổ khóa trên các hồ sơ cá nhân:

-- Session 1 
START TRANSACTION; 
UPDATE t_lock 
SET  val = 3 
WHERE id IN (1, 2) 

-- Session 2 
START TRANSACTION; 
INSERT 
INTO t_lock 
VALUES (3, 3) 
-- Success 

Truy vấn này, trong khi làm như vậy, thực hiện một range quét và đặt một khoảng cách khóa sau giá trị khóa 2, sẽ không cho phép chèn giá trị khóa 3:

-- Session 1 
START TRANSACTION; 
UPDATE t_lock 
SET  val = 3 
WHERE id BETWEEN 1 AND 2 

-- Session 2 
START TRANSACTION; 
INSERT 
INTO t_lock 
VALUES (3, 3) 
-- Locks 
+0

Cảm ơn câu trả lời của bạn, nó không thực sự chạy chậm mặc dù .. Nó chỉ có vẻ làm điều đó một lần trong một thời gian, tôi chỉ cần chạy nó và phải mất 0.0014s do đó, không có vấn đề với tốc độ thực tế? –

+0

Điều này sẽ chạy chậm nếu bạn sẽ tìm kiếm các từ khóa xuất hiện thường xuyên. Giả sử, nếu bạn tìm kiếm từ khóa ''professional'' và' 1.000.000' sản phẩm chứa từ khóa này, công cụ sẽ cần truy xuất tất cả các bản ghi này và sắp xếp chúng theo thứ tự sắp xếp của bạn. Điều này có thể được cải thiện với một vị từ thông thường (không phải toàn văn) bằng cách tạo ra một chỉ mục tổng hợp, nhưng, thật không may, 'MySQL' không cho phép trộn các khóa fulltext và không fulltext trong một chỉ mục. – Quassnoi

+0

Tôi thấy, tốt, vì mục đích của tôi vào lúc này, tôi nghĩ tốc độ chung của vấn đề này sẽ không thành vấn đề. Cảm ơn –

0

Bật truy vấn chậm, điều này sẽ cho bạn ý tưởng về việc mất nhiều thời gian để thực thi có thời gian chờ.

http://dev.mysql.com/doc/refman/5.1/en/slow-query-log.html

Chọn truy vấn chậm nhất và tối ưu hóa điều đó. sau đó chạy một lúc và lặp lại.

Có một số thông tin tuyệt vời và các công cụ ở đây http://hackmysql.com/nontech

DC

UPDATE:

Hoặc bạn gặp rắc rối mạng gây ra thời gian chờ, nếu bạn đang sử dụng một ví dụ mysql địa phương thì đó là khó xảy ra , HOẶC một cái gì đó đang khóa một bảng quá lâu gây ra một thời gian chờ. quá trình khóa bàn hoặc bảng quá lâu sẽ được liệt kê trong nhật ký chậm dưới dạng truy vấn chậm. bạn cũng có thể nhận được truy vấn nhật ký chậm để hiển thị bất kỳ truy vấn nào không sử dụng một chỉ mục dẫn đến truy vấn không hiệu quả.

Nếu bạn gặp sự cố xảy ra khi đang có mặt thì bạn cũng có thể sử dụng công cụ như phpmyadmin hoặc dòng lệnh để chạy "SHOW PROCESSLIST \ G", điều này sẽ cung cấp cho bạn danh sách các truy vấn đang chạy trong khi sự cố đang xảy ra.

Bạn nghĩ rằng vấn đề nằm trong câu lệnh chèn của bạn, do đó, có điều gì đó đang khóa bảng đó. do đó bạn cần phải tìm những gì đang khóa bảng đó, do đó bạn cần phải tìm những gì đang chạy quá chậm khóa bảng của nó quá lâu. Truy vấn chậm là một cách để làm điều đó.

Những điều khác để nhìn vào

CPU - là nó nhàn rỗi hoặc chạy ở đầy đủ tấm da

IO - là io gây vụ cướp

RAM - là bạn trao đổi tất cả các thời gian (sẽ gây ra io quá mức)

Sản phẩm bảng_search_query có sử dụng chỉ mục không?

Khóa chính là gì?

Nếu chỉ mục của bạn sử dụng các chuỗi quá dài? bạn có thể xây dựng một tệp chỉ mục lớn gây ra chèn rất chậm (nhật ký truy vấn chậm cũng sẽ cho thấy)

Và có vấn đề ở đâu đó, nhưng bạn phải bắt đầu ở đâu đó phải không.

DC

+0

Một lần nữa, không có vấn đề tốc độ, khác với một thời gian chờ, khi nó hoạt động nó hoạt động ở một tốc độ rất hợp lý. Thời gian chờ là do khóa, không phải là vấn đề tốc độ thực tế. –

+0

Xem cập nhật ở trên – DeveloperChris

0

Hãy thử gói của bạn EXECUTE như sau:

SET CẤP PHIÊN GIAO DỊCH cô lập ĐỌC không bị giam;

THỰC HIỆN TheSelect USING @keywords, @keywords, @startOffset, @itemsToReturn;

THIẾT LẬP TIẾP CẬN GIAO DIỆN CHUYÊN BIỆT ĐÃ ĐỌC LẠI;

Tôi làm một cái gì đó tương tự trong TSQL cho tất cả các báo cáo được lưu trữ proc và tìm kiếm nơi đọc lặp lại không quan trọng để giảm khóa/chặn các vấn đề với các quy trình khác đang chạy trên cơ sở dữ liệu.

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