Retail inventory system Mysql query optimization

2019-08-15 02:36发布

问题:

I'm looking to optimize the following Mysql query that is used to calculate the cost of inventory for a number of stores, I'm running the following query through a PHP loop for each distinct store and outputting the result:

Query:

SELECT

    SUM((((

    (SELECT COALESCE(SUM(facturas_fabrica.cantidad), 0)

    FROM facturas_fabrica

    INNER JOIN entradas_pedidos_productos ON 
    entradas_pedidos_productos.clave = facturas_fabrica.entradas_pedidos_productos_clave

    INNER JOIN entradas_pedidos ON entradas_pedidos.clave = entradas_pedidos_productos.entradas_pedidos_clave

    WHERE entradas_pedidos_productos.producto_id = productos.id 
    AND facturas_fabrica.procesado_local = 1 AND entradas_pedidos.sucursal_id = '.$row['id'].' # store id   
    AND DATE(facturas_fabrica.fecha_procesada) <= DATE(NOW()))


    -

    (SELECT COALESCE(SUM(cantidad), 0) 

    FROM facturas_contenido

    WHERE producto_id = productos.id AND facturas_contenido.sucursal_id = '.$row['id'].'
    AND DATE(facturas_contenido.fecha_creacion) <= DATE(NOW()))

    +

    (SELECT COALESCE(SUM(cantidad), 0) 

    FROM notas_de_credito_contenido

    WHERE producto_id = productos.id AND notas_de_credito_contenido.sucursal_id = '.$row['id'].'
    AND DATE(notas_de_credito_contenido.fecha_creacion) <= DATE(NOW()))

    -

    (SELECT COALESCE(SUM(salidas_devoluciones.cantidad), 0) 

    FROM salidas_devoluciones

    WHERE producto_id = productos.id AND (estado = 2 OR estado = 3) AND modulo != 2 AND salidas_devoluciones.sucursal_id = '.$row['id'].' # store id
    AND DATE(salidas_devoluciones.fecha_envio) <= DATE(NOW()))   

    ) * productos.costo) / 100) ) AS "'.$row['clave'].'" # store name 

FROM productos WHERE 1

(I'm only keeping fields relevant to the query)

Table 1:

CREATE TABLE `productos` (
  `id` int(10) unsigned NOT NULL,
  `costo` int(10) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `costo` (`costo`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Table 2:

CREATE TABLE `facturas_fabrica` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `clave` bigint(20) unsigned NOT NULL,
  `entradas_pedidos_productos_clave` bigint(20) unsigned NOT NULL,
  `cantidad` tinyint(3) unsigned NOT NULL,
  `procesado_local` tinyint(1) NOT NULL DEFAULT '0',
  `fecha_procesada` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `clave_UNIQUE` (`clave`),
  KEY `fk_entradas_pedidos_productos_clave_idx` (`entradas_pedidos_productos_clave`),
  KEY `facturas_fabrica_procesado_local` (`procesado_local`),
  KEY `facturas_fabrica_cantidad` (`cantidad`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

--
-- Constraints for table `facturas_fabrica`
--
ALTER TABLE `facturas_fabrica`
  ADD CONSTRAINT `fk_entradas_pedidos_productos_clave` FOREIGN KEY (`entradas_pedidos_productos_clave`) REFERENCES `entradas_pedidos_productos` (`clave`) ON DELETE NO ACTION ON UPDATE NO ACTION;

Table 3:

CREATE TABLE `entradas_pedidos_productos` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `clave` bigint(20) unsigned NOT NULL,
  `entradas_pedidos_clave` bigint(20) unsigned NOT NULL,
  `producto_id` int(10) unsigned NOT NULL,
  `cantidad` tinyint(3) unsigned NOT NULL,

  PRIMARY KEY (`id`),
  UNIQUE KEY `clave_UNIQUE` (`clave`),
  KEY `fk_pedidos_producto_id_idx` (`producto_id`),
  KEY `fk_pedidos_productos_pedido_clave_idx` (`entradas_pedidos_clave`),
  KEY `entradas_productos_cantidad` (`cantidad`),
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

--
-- Constraints for table `entradas_pedidos_productos`
--
ALTER TABLE `entradas_pedidos_productos`
  ADD CONSTRAINT `fk_pedidos_productos_pedido_clave` FOREIGN KEY (`entradas_pedidos_clave`) REFERENCES `entradas_pedidos` (`clave`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  ADD CONSTRAINT `fk_pedidos_productos_producto_id` FOREIGN KEY (`producto_id`) REFERENCES `productos` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION;

Table 4:

CREATE TABLE `entradas_pedidos` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `clave` bigint(20) unsigned NOT NULL,
  `sucursal_id` tinyint(3) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `clave_UNIQUE` (`clave`),
  KEY `clave` (`clave`),
  KEY `entradas_sucursal` (`sucursal_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

--
-- Constraints for table `entradas_pedidos`
--
ALTER TABLE `entradas_pedidos`
  ADD CONSTRAINT `fk_entradas_pedidos_sucursal_is` FOREIGN KEY (`sucursal_id`) REFERENCES `sucursales` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION;

Table 5:

CREATE TABLE `facturas_contenido` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `clave` bigint(20) unsigned NOT NULL,
  `sucursal_id` tinyint(3) NOT NULL,
  `producto_id` int(10) unsigned NOT NULL,
  `cantidad` tinyint(3) unsigned NOT NULL,
  `fecha_creacion` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `clave_factura_contenido` (`clave`),
  KEY `fk_orden_contenido_producto_id_idx` (`producto_id`),
  KEY `facturas_contenido_cantidad` (`cantidad`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

--
-- Constraints for table `facturas_contenido`
--
ALTER TABLE `facturas_contenido`
  ADD CONSTRAINT `fk_facturas_clave` FOREIGN KEY (`factura_clave`) REFERENCES `facturas` (`clave`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  ADD CONSTRAINT `fk_facturas_contenido_producto_id` FOREIGN KEY (`producto_id`) REFERENCES `productos` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION;

Table 6:

CREATE TABLE `notas_de_credito_contenido` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `clave` bigint(20) unsigned NOT NULL,
  `sucursal_id` tinyint(3) NOT NULL,
  `producto_id` int(10) unsigned NOT NULL,
  `cantidad` tinyint(3) unsigned NOT NULL,
  `fecha_creacion` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `clave_nota_de_credito_contenido` (`clave`),
  KEY `fk_nc_clave_idx` (`nc_clave`),
  KEY `fk_ordenes_contenido_clave_idx` (`nc_facturas_contenido_clave`),
  KEY `notas_de_credito_cantidad` (`cantidad`),
  KEY `notas_de_credito_producto_id` (`producto_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

--
-- Constraints for dumped tables
--

--
-- Constraints for table `notas_de_credito_contenido`
--
ALTER TABLE `notas_de_credito_contenido`
  ADD CONSTRAINT `fk_facturas_contenido_clave` FOREIGN KEY (`nc_facturas_contenido_clave`) REFERENCES `facturas_contenido` (`clave`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  ADD CONSTRAINT `fk_nc_clave` FOREIGN KEY (`nc_clave`) REFERENCES `notas_de_credito` (`clave`) ON DELETE NO ACTION ON UPDATE NO ACTION;

Table 7:

CREATE TABLE `salidas_devoluciones` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `clave` bigint(20) unsigned NOT NULL,
  `producto_id` int(10) unsigned NOT NULL,
  `cantidad` tinyint(3) unsigned NOT NULL,
  `sucursal_id` tinyint(3) NOT NULL,
  `fecha_envio` timestamp NULL DEFAULT NULL,
  `estado` tinyint(3) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `clave_UNIQUE` (`clave`),
  KEY `salidas_devoluciones_cantidad` (`cantidad`),
  KEY `fk_salidas_producto_id_idx` (`producto_id`),
  KEY `devoluciones_estado` (`estado`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

--
-- Constraints for table `salidas_devoluciones`
--
ALTER TABLE `salidas_devoluciones`
  ADD CONSTRAINT `fk_salidas_producto_id` FOREIGN KEY (`producto_id`) REFERENCES `productos` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION;

The problem is because of the large amount of stores and movements in each store the query is becoming increasingly heavy, and because inventory is calculated from the beginning of each store's history it only gets slower with time.

What could I do to optimize this scheme?