【问题标题】:Why is this MySQL query so slow to execute?为什么这个 MySQL 查询执行起来这么慢?
【发布时间】:2017-10-12 06:36:00
【问题描述】:

我提供了包含真实测试数据的 PHP 查询和数据库表。为什么 MySQL 查询执行这么慢?有什么我可以改变的来加快速度吗?执行时间约为 40 秒,表中约有 2929 条记录。

查询;

$invoice_details_query = mysqli_query($con,"SELECT i.*, 

ifnull(SUM(ip.invoice_payment_amount),0) as paid, 
(i.invoice_total_amount_exc_vat + i.invoice_total_vat_amount) - ifnull(SUM(ip.invoice_payment_amount),0) as due 
FROM accounts_invoice i 
LEFT JOIN accounts_invoice_payment ip 
ON ip.invoice_payment_invoice_id = i.invoice_id 
WHERE i.invoice_posted='1'
GROUP BY i.invoice_id 
HAVING due>0 
ORDER BY i.invoice_id ASC") or die(mysql_error());

$total = mysqli_num_rows($invoice_details_query);

数据库结构(无数据);

-- phpMyAdmin SQL Dump
-- version 4.6.6
-- https://www.phpmyadmin.net/
--
-- Host: localhost:3306
-- Generation Time: May 12, 2017 at 09:56 PM
-- Server version: 5.6.35
-- PHP Version: 5.6.30

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";


/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;

--
-- Database: `propsyst_main`
--

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

--
-- Table structure for table `accounts_invoice`
--

CREATE TABLE `accounts_invoice` (
  `invoice_id` int(11) NOT NULL,
  `invoice_token` varchar(40) COLLATE utf8_bin DEFAULT NULL,
  `invoice_customer_type` tinyint(4) DEFAULT NULL,
  `invoice_customer` int(11) DEFAULT NULL,
  `invoice_date` date DEFAULT NULL,
  `invoice_due_date` date DEFAULT NULL,
  `invoice_property_id` int(11) DEFAULT NULL,
  `invoice_tenancy_id` int(11) DEFAULT NULL,
  `invoice_branch` int(11) DEFAULT NULL,
  `invoice_payment_terms` tinyint(4) DEFAULT NULL,
  `invoice_notes` text COLLATE utf8_bin,
  `invoice_total_amount_exc_vat` decimal(10,2) DEFAULT NULL,
  `invoice_total_vat_amount` decimal(10,2) DEFAULT NULL,
  `invoice_posted` tinyint(4) DEFAULT '0',
  `invoice_overdue_reminders` tinyint(4) NOT NULL DEFAULT '1',
  `invoice_date_created` datetime DEFAULT NULL,
  `invoice_date_updated` datetime DEFAULT NULL,
  `invoice_date_posted` datetime DEFAULT NULL,
  `invoice_created_by` int(11) DEFAULT NULL,
  `invoice_updated_by` int(11) DEFAULT NULL,
  `invoice_posted_by` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

--
-- Indexes for dumped tables
--

--
-- Indexes for table `accounts_invoice`
--
ALTER TABLE `accounts_invoice`
  ADD PRIMARY KEY (`invoice_id`);

--
-- AUTO_INCREMENT for dumped tables
--

--
-- AUTO_INCREMENT for table `accounts_invoice`
--
ALTER TABLE `accounts_invoice`
  MODIFY `invoice_id` int(11) NOT NULL AUTO_INCREMENT;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

解释分析;

 Current selection does not contain a unique column. Grid edit, checkbox, Edit, Copy and Delete features are not available. 

Your SQL query has been executed successfully.

explain accounts_invoice



invoice_id  int(11) NO  PRI     auto_increment  
invoice_token   varchar(40) YES             
invoice_customer_type   tinyint(4)  YES             
invoice_customer    int(11) YES             
invoice_date    date    YES             
invoice_due_date    date    YES             
invoice_property_id int(11) YES             
invoice_tenancy_id  int(11) YES             
invoice_branch  int(11) YES             
invoice_payment_terms   tinyint(4)  YES             
invoice_notes   text    YES             
invoice_total_amount_exc_vat    decimal(10,2)   YES             
invoice_total_vat_amount    decimal(10,2)   YES             
invoice_posted  tinyint(4)  YES     0       
invoice_overdue_reminders   tinyint(4)  NO      1       
invoice_date_created    datetime    YES             
invoice_date_updated    datetime    YES             
invoice_date_posted datetime    YES             
invoice_created_by  int(11) YES             
invoice_updated_by  int(11) YES             
invoice_posted_by   int(11) YES             

具有真实测试数据的数据库;

Download MySQL data

【问题讨论】:

  • 您是否创建了索引?性能问题应该包括EXPLAIN ANALYZE和一些关于表大小、索引、当前时间性能、期望时间等的信息。Slow是一个相对术语,我们需要一个真实的值来比较。 MySQL
  • @JuanCarlosOropeza 我刚刚将数据库结构转储到问题中。
  • MyISAM 没有索引?这真的不是成功的秘诀。尽可能使用 InnoDB,它是一个适当的、事务性的、支持 MVCC 的数据库引擎,更易于扩展,并且可以在 WHEREGROUP BY 子句中使用的任何列上添加索引。
  • @tadman 您建议在哪些列中添加索引?
  • 首先为i.invoice_posted 创建一个索引,然后为` i.invoice_id `创建另一个索引,最后在复合索引中为两者创建第三个索引。然后用 EXPLAIN PLAN 测试结果

标签: mysql sql performance


【解决方案1】:

请为每张桌子提供SHOW CREATE TABLE。听起来您缺少任何以 invoice_payment_invoice_id 开头的索引。

此外,如果只过帐一小部分发票,那么INDEX(invoice_posted, invoice_id) 将是有益的。

【讨论】:

  • 谢谢。我已经在 invoice_id、invoice_posted 和 invoice_payment_invoice_id 上创建了索引,并且查询的执行速度要快得多。您还有什么其他建议可以进一步提高性能吗?
  • 我打算让你在最后一对上有一个“复合”索引,而不是两个单独的索引。有关creating indexes 的更多信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-03-11
  • 2012-06-13
  • 1970-01-01
  • 2011-10-18
  • 2020-03-19
  • 2014-03-12
  • 2011-02-28
相关资源
最近更新 更多