2009-12-29 17 views
6

EDIT:¿El procedimiento almacenado de MySQL causa problemas?

He reducido mi mysql de tiempo de espera hasta la siguiente línea:

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

Alguna idea de por qué esto podría causar un problema? ¡No puedo resolverlo!

Hola chicos, he escrito un procedimiento almacenado para buscar productos en ciertas categorías, debido a ciertas restricciones que encontré, no pude hacer lo que quería (limitando, pero al mismo tiempo devolviendo el número total de filas encontrado, con clasificación, etc.)

Se divide una cadena de Id. de categoría, de 1,2,3 en una tabla temporal, luego se crea la consulta de búsqueda de texto completo en función de las opciones y los límites de clasificación, ejecuta la cadena de consulta y luego selecciona el número total de resultados.

Ahora, sé que no soy un gurú de MySQL, muy lejos de eso, lo tengo funcionando, pero sigo recibiendo tiempos muertos con búsquedas de productos, etc., así que estoy pensando que esto puede estar causando algún tipo de de problema?

¿Alguien tiene alguna idea de cómo puedo arreglar esto, o incluso hacerlo de una manera mucho mejor que probablemente no conozca?

Gracias ..

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 ; 

cualquier ayuda es muy muy apreciados!

+1

¿Sería posible obtener una TABLA DESCRIBE para las tablas utilizadas en esto? Creo que podemos reducir la complicación y, posiblemente, acelerarla también si tuviera más ojos en las mesas. –

+0

I segundo comentario kevins. muy poco para seguir. – DeveloperChris

Respuesta

4

Hay poco que puede hacer con esta consulta.

Prueba esto:

  1. Crear una PRIMARY KEY en categoryIds (categoryId)

    • Asegúrese de que supplier (supplied_id) es una PRIMARY KEY

    • Asegúrese de que category_product (ProductID, CategoryID) (en este orden) es un PRIMARY KEY , o tiene un índice con ProductID líder.

Actualización:

Si se trata de INSERT que causa el problema y product_search_query en una tabla MyISAM el problema puede estar con MyISAM de bloqueo.

MyISAM bloquea toda la tabla si decide insertar una fila en un bloque libre en el medio de la tabla que puede causar los tiempos de espera.

Intente utilizar INSERT DELAYED lugar:

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

Esto pondrá los registros en la cola de inserción y volver inmediatamente. El registro se agregará más tarde de forma asíncrona.

Tenga en cuenta que puede perder información si el servidor muere después de que se emite el comando pero antes de que realmente se inserten los registros.

Actualización:

Desde su mesa es InnoDB, puede ser un problema con el bloqueo de tablas. INSERT DELAYED no es compatible con InnoDB.

Dependiendo de la naturaleza de la consulta, DML consultas en InnoDB tabla pueden colocar bloqueos de espacio que bloquearán las inserciones.

Por ejemplo:

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); 

Esta consulta realiza ref exploraciones y coloca las cerraduras de los registros individuales:

-- 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 

Esta consulta, mientras que haciendo lo mismo, realiza un escaneo range y coloca una brecha bloquear después del valor de clave 2, que no permitirá insertar el valor de clave 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

Gracias por su respuesta, en realidad no está funcionando lentamente ... Parece que lo hace de vez en cuando, simplemente lo ejecuté y tomó 0.0014s, así que ¿no hay problema con la velocidad real? –

+0

Esto se ejecutará lentamente si va a buscar las palabras clave que ocurren con frecuencia. Supongamos que si busca la palabra clave "profesional" y los productos "1,000,000" contienen esta palabra clave, el motor deberá recuperar todos estos registros y ordenarlos según su orden de clasificación. Esto podría mejorarse con un predicado habitual (no con texto completo) creando un índice compuesto, pero, desafortunadamente, 'MySQL' no permite mezclar texto completo y claves no completas en un índice. – Quassnoi

+0

Veo, bueno, para mis propósitos en este momento, creo que la velocidad general de esto no será un problema. Gracias –

0

Active las consultas lentas, que le darán una idea de lo que tarda tanto en ejecutarse que hay un tiempo de espera.

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

escoger la consulta más lento y optimizar eso. luego corre por un rato y repite.

Hay algo de excelente información y herramientas aquí http://hackmysql.com/nontech

DC

ACTUALIZACIÓN:

O tienes un problema de red haciendo que el tiempo de espera, si está utilizando una instancia de MySQL local, entonces eso es poco probable , O algo está bloqueando una tabla durante demasiado tiempo causando un tiempo de espera. el proceso que bloquea la tabla o las tablas durante demasiado tiempo se mostrará en el registro lento como una consulta lenta. también puede obtener la consulta de registro lento para mostrar las consultas que no pueden usar un índice que da como resultado una consulta ineficiente.

Si puede tener el problema mientras está presente, también puede usar una herramienta como phpmyadmin o la línea de comandos para ejecutar "MOSTRAR LISTA DE PROCESOS \ G", esto le dará una lista de las consultas que se están ejecutando mientras el problema está ocurriendo.

Cree que el problema está en su instrucción de inserción, por lo tanto, algo está bloqueando esa tabla. por lo tanto, debe encontrar lo que está bloqueando esa tabla, por lo tanto, debe encontrar lo que está funcionando, por lo que es muy lento bloquear la tabla durante demasiado tiempo. Las consultas lentas son una forma de hacerlo.

Otras cosas que ver

CPU - es inactivo o funcionando a toda velocidad

IO - es io que causan atracos

RAM - estás intercambiando todo el tiempo (hará que io excesiva)

¿La tabla product_search_query usa un índice?

¿Cuál es la clave principal?

Si su índice usa cadenas que son demasiado largas? usted puede construir un gran archivo de índice que causa inserciones muy lentas (el registro lento de consultas también lo mostrará)

Y sí, el problema puede ser otro, pero debe comenzar en alguna parte, ¿no es así?

DC

+0

Una vez más, no hay problemas de velocidad, aparte de un tiempo de espera, cuando funciona funciona a una velocidad muy razonable. El tiempo de espera es causado por el bloqueo, no es un problema de velocidad real. –

+0

Ver la actualización anterior – DeveloperChris

0

trate de envolver su EJECUTAR con lo siguiente:

SET nivel de sesión TRANSACCIÓN AISLAMIENTO READ;

EJECUTAR TheSelect USING @keywords, @keywords, @startOffset, @itemsToReturn;

SET SESIÓN TRANSACCIÓN NIVEL DE AISLAMIENTO REPETIBLE LEÍDO;

Hago algo similar en TSQL para todos los informes almacenados de procesos y búsquedas donde las lecturas repetibles no son importantes para reducir los problemas de bloqueo/bloqueo con otros procesos que se ejecutan en la base de datos.

Cuestiones relacionadas