Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/65.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql select查询,带索引的子查询执行时间长(28秒)_Mysql_Subquery - Fatal编程技术网

Mysql select查询,带索引的子查询执行时间长(28秒)

Mysql select查询,带索引的子查询执行时间长(28秒),mysql,subquery,Mysql,Subquery,我试图在MYsql上运行下面的查询,该查询运行时间太长。 我需要为每个供应商提取: 采购总额 总销售额 如果供应商的期初余额不同于null,则在子查询的where子句中使用,否则使用“2020-01-01” 以下是我正在使用的查询: SELECT sup.name AS supplier_name, sup.id AS supplier_id, sup.opening_balance_date, sup.opening_balance AS opening_balance, ( SEL

我试图在MYsql上运行下面的查询,该查询运行时间太长。 我需要为每个供应商提取:

采购总额 总销售额 如果供应商的期初余额不同于null,则在子查询的where子句中使用,否则使用“2020-01-01”

以下是我正在使用的查询:

SELECT 
sup.name AS supplier_name,
sup.id AS supplier_id,
sup.opening_balance_date,
sup.opening_balance AS opening_balance,
(
    SELECT
    IFNULL(SUM(pop.quantity * pop.cost),0)   AS total_purchases
    FROM purchase_order_products pop
    JOIN purchase_order po ON
    pop.purchase_order_id = po.id
    WHERE
    DATE(po.created_at) >= IFNULL(sup.opening_balance_date, '2020-01-01')  
    AND DATE(po.created_at) < '2020-03-01'
    AND po.status = 'approved'
    AND po.supplier_id = sup.id
) as total_purchases,
(
    SELECT 
    IFNULL(sum(soi.total_cost),0) AS total_sales              
    FROM
    sales_order_item soi 
    JOIN sales_order so use index (date_status_completed) ON
    so.id = soi.sales_order_id
    WHERE
    soi.total_cost > 0
    AND soi.supplier_id = sup.id
    AND so.order_status = 'complete' 
    AND so.completed_returned = 0
    AND so.desired_delivery_date >= IFNULL(sup.opening_balance_date, '2020-01-01')   
) AS total_sales
FROM supplier sup
WHERE sup.is_active = 1
group by sup.id
ORDER BY sup.name;
我认为问题就在这里:soi.supplier\u id=sup.id

下面是解释

这里是数据库

创建查询:

--
-- Table structure for table `purchase_order`
--

CREATE TABLE `purchase_order` (
  `id` int(11) NOT NULL,
  `supplier_id` int(11) NOT NULL,
  `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `status` varchar(150) DEFAULT 'Pending',
  `total` float NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- --------------------------------------------------------

--
-- Table structure for table `purchase_order_products`
--

CREATE TABLE `purchase_order_products` (
  `id` int(11) NOT NULL,
  `purchase_order_id` int(11) NOT NULL,
  `product_id` int(11) NOT NULL,
  `quantity` int(50) NOT NULL,
  `cost` decimal(15,3) NOT NULL,
  `reporting_quantity` int(11) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- --------------------------------------------------------


--
-- Table structure for table `sales_order`
--

CREATE TABLE `sales_order` (
  `id` varchar(20) NOT NULL,
  `order_status` varchar(50) DEFAULT NULL,
  `desired_delivery_date` date DEFAULT NULL,
  `completed_returned` int(1) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- --------------------------------------------------------

--
-- Table structure for table `sales_order_item`
--

CREATE TABLE `sales_order_item` (
  `id` varchar(20) NOT NULL,
  `sales_order_id` varchar(20) NOT NULL,
  `total_cost` float NOT NULL DEFAULT '0',
  `supplier_id` int(11) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- --------------------------------------------------------

--
-- Table structure for table `supplier`
--

CREATE TABLE `supplier` (
  `id` int(11) NOT NULL,
  `name` varchar(400) NOT NULL,
  `opening_balance` decimal(10,2) NOT NULL DEFAULT '0.00',
  `opening_balance_date` date DEFAULT NULL,
  `is_active` tinyint(4) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- --------------------------------------------------------


--
-- Indexes for dumped tables
--

--
-- Indexes for table `credit_note`

--
-- Indexes for table `purchase_order`
--
ALTER TABLE `purchase_order`
  ADD PRIMARY KEY (`id`),
  ADD KEY `id` (`id`),
  ADD KEY `supplier_id` (`supplier_id`),
  ADD KEY `created_at` (`created_at`,`status`),
  ADD KEY `supplier_id_2` (`supplier_id`,`created_at`),
  ADD KEY `id_date_status` (`supplier_id`,`created_at`,`status`) USING BTREE;

--
-- Indexes for table `purchase_order_products`
--
ALTER TABLE `purchase_order_products`
  ADD PRIMARY KEY (`id`),
  ADD KEY `purchase_order_id` (`purchase_order_id`),
  ADD KEY `product_id` (`product_id`),
  ADD KEY `cost` (`cost`,`reporting_quantity`);

--
-- Indexes for table `sales_order`
--
ALTER TABLE `sales_order`
  ADD PRIMARY KEY (`id`),
  ADD UNIQUE KEY `idx_id` (`id`),
  ADD KEY `idx_desired_delivery_date` (`desired_delivery_date`),
  ADD KEY `date_status_completed` (`order_status`,`desired_delivery_date`,`completed_returned`) USING BTREE,
  ADD KEY `completed_returned` (`completed_returned`),
  ADD KEY `order_status` (`order_status`),
  ADD KEY `order_status_2` (`order_status`,`completed_returned`);

--
-- Indexes for table `sales_order_item`
--
ALTER TABLE `sales_order_item`
  ADD PRIMARY KEY (`id`),
  ADD KEY `sales_order_id` (`sales_order_id`),
  ADD KEY `reporting_supplier` (`supplier_id`) USING BTREE,
  ADD KEY `total_cost` (`total_cost`),
  ADD KEY `supplier_cost` (`supplier_id`,`total_cost`) USING BTREE,
  ADD KEY `supplier_id` (`supplier_id`);

--
-- Indexes for table `supplier`
--
ALTER TABLE `supplier`
  ADD PRIMARY KEY (`id`),
  ADD KEY `id` (`id`),
  ADD KEY `is_active` (`is_active`);


--
-- AUTO_INCREMENT for table `purchase_order`
--
ALTER TABLE `purchase_order`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=26763;
--
-- AUTO_INCREMENT for table `purchase_order_products`
--
ALTER TABLE `purchase_order_products`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=41884;

--
-- AUTO_INCREMENT for table `supplier`
--
ALTER TABLE `supplier`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=182;

没有足够的信息来回答这个问题,但是您在第二个子查询中使用的USE INDEX子句可能会迫使MySQL扫描更多的行。尝试删除使用索引日期\u状态\u已完成。

主键是唯一键:

ADD PRIMARY KEY (`id`),
ADD KEY `id` (`id`),  -- Toss this; it is redundant
不要混合使用INT和VARCHAR:

当您不需要执行以下操作时,不要使用日期:

DATE(po.created_at) < '2020-03-01'

对mysql版本8.0.19上测试的查询的修订,假设purchase\u order和sales\u order\u item表彼此稀疏,但两者都应该有一个外键引用supplier表,但不一定是supplier上的任何相同记录

通过将“采购订单”或“销售订单”项目下推到单个EXISTS子查询中,然后将另一个转换为左外部联接,可以减少必要的扫描次数。 SUM的功能消除了对采购订单产品执行空合并操作的需要。 由于sales_order.completed_returned是一个布尔整数,因此我们可以将其合并到1-so.completed_returned中,将“returned”项目的总成本转换为聚合中无害的零;同样,最大化也避免了总成本>0筛选条件的需要。 此外,如果每个采购订单供应商也是销售订单供应商,则可以使用内部连接替换左侧外部连接,以获得正确的输出。 最后,如前所述,这里也不用麻烦使用DATE,因为条件已经暗示了它

挑选 供应商名称作为供应商名称, 作为供应商的sup.id\u id, MINsup.期初余额日期作为期初余额日期, MINsup.期初余额作为期初余额, 总采购数量*总采购成本, 合并最大soi.总成本之和,0*1-so.已完成退货,0作为总销售额 来自供应商支持、采购订单和产品pop 左侧外部连接销售\订单\ soi上的项目soi.supplier\u id=sup.id 左外接销售订单等 so.id=soi.sales\u order\u id和 so.order_status='complete'和 so.desired_delivery_date>=合并期初余额_date,'2020-01-01' 其中sup.is_active=1 存在 选择1 来自采购订单po 哪里 订单创建日期>=合并支持期初余额日期'2020-01-01' 并在<'2020-03-01'处创建po.U 采购订单状态=‘已批准’ 采购订单供应商id=供应商id 和pop.purchase\u order\u id po.id 按辅助id、辅助名称分组 按供应商名称订购

解释格式=树

-> Sort: <temporary>.name
    -> Table scan on <temporary>
        -> Aggregate using temporary table
            -> Nested loop inner join  (cost=1.75 rows=1)
                -> Nested loop inner join  (cost=1.40 rows=1)
                    -> Nested loop left join  (cost=1.05 rows=1)
                        -> Nested loop left join  (cost=0.70 rows=1)
                            -> Index lookup on sup using is_active (is_active=1)  (cost=0.35 rows=1)
                            -> Index lookup on soi using reporting_supplier (supplier_id=sup.id)  (cost=0.35 rows=1)
                        -> Filter: ((so.order_status = \'complete\') and (so.desired_delivery_date >= coalesce(sup.opening_balance_date,\'2020-01-01\')))  (cost=0.35 rows=1)
                            -> Single-row index lookup on so using PRIMARY (id=soi.sales_order_id)  (cost=0.35 rows=1)
                    -> Filter: ((po.created_at >= coalesce(sup.opening_balance_date,\'2020-01-01\')) and (po.created_at < TIMESTAMP\'2020-03-01 00:00:00\') and (po. = \'approved\'))  (cost=0.35 rows=1)
                        -> Index lookup on po using supplier_id (supplier_id=sup.id)  (cost=0.35 rows=1)
                -> Index lookup on pop using purchase_order_id (purchase_order_id=po.id), with index condition: (pop.purchase_order_id <=> po.id)  (cost=0.35 rows=1)
看看这在您的用例中是否能更好地工作——如果不知道所有相关表格的内容,就很难确切地知道重新工作将如何进行


粗略地看一下解释计划表明,可以通过对该查询使用半连接和BNL/NO\n优化来进一步优化。我已经删除了这个:使用索引日期\u状态\u完成。相同的结果以文本形式写出表格和字段,而不仅仅是屏幕抓图,张贴每个表格中的一些示例数据,以便人们可以在不准备的情况下制作SQLFIDLE。至少张贴SHOW CREATE table sales_order的结果。索引日期\u status\u completed似乎不太理想。我在文本中添加了表结构。是否有公共场所可以导入我的数据库,您可以在那里访问它?这对我帮助很大。我用你的提示现在查询执行时间是3秒。感谢you@Mohammad-让我们看看解释选择。。。变更后的等;可能还有更多的事情需要调整。
DATE(po.created_at) < '2020-03-01'
po.created_at < '2020-03-01'
sup:  (is_active, id)
so:  (completed_returned, order_status, desired_delivery_date, id)
soi:  (supplier_id, total_cost, sales_order_id)
po:  (supplier_id, status, created_at, id)
-> Sort: <temporary>.name
    -> Table scan on <temporary>
        -> Aggregate using temporary table
            -> Nested loop inner join  (cost=1.75 rows=1)
                -> Nested loop inner join  (cost=1.40 rows=1)
                    -> Nested loop left join  (cost=1.05 rows=1)
                        -> Nested loop left join  (cost=0.70 rows=1)
                            -> Index lookup on sup using is_active (is_active=1)  (cost=0.35 rows=1)
                            -> Index lookup on soi using reporting_supplier (supplier_id=sup.id)  (cost=0.35 rows=1)
                        -> Filter: ((so.order_status = \'complete\') and (so.desired_delivery_date >= coalesce(sup.opening_balance_date,\'2020-01-01\')))  (cost=0.35 rows=1)
                            -> Single-row index lookup on so using PRIMARY (id=soi.sales_order_id)  (cost=0.35 rows=1)
                    -> Filter: ((po.created_at >= coalesce(sup.opening_balance_date,\'2020-01-01\')) and (po.created_at < TIMESTAMP\'2020-03-01 00:00:00\') and (po. = \'approved\'))  (cost=0.35 rows=1)
                        -> Index lookup on po using supplier_id (supplier_id=sup.id)  (cost=0.35 rows=1)
                -> Index lookup on pop using purchase_order_id (purchase_order_id=po.id), with index condition: (pop.purchase_order_id <=> po.id)  (cost=0.35 rows=1)