优化包含多个连接的datetime列的MySQL SELECT

时间:2014-08-01 14:00:31

标签: mysql optimization

我有这个查询返回我想要的内容。

SELECT DISTINCT c.cust_id 
  FROM tbCustomers AS c 
  JOIN tbOrders AS o 
    ON o.order_custid = c.cust_id 
  JOIN tbPayments AS p 
    ON p.pay_custid = c.cust_id 
 WHERE (
         DATE(o.order_date) > DATE_ADD(NOW(), INTERVAL -14 DAY)
     AND o.order_status = '3' 
     AND o.order_exported = '0'
       ) 
    OR (
         DATE(p.pay_date) > DATE_ADD(NOW(), INTERVAL -14 DAY) 
     AND p.pay_exported = '0'
       )

但是执行速度相对较慢,我想找到一种方法来加快速度。 谁能给我一些指示?

编辑:

按要求解析和创建

说明:

enter image description here (删除了数据库名称)

CREATE(S):

CREATE TABLE IF NOT EXISTS `tbCustomers` (
`cust_id` int(11) NOT NULL,
  `cust_roundid` int(11) DEFAULT NULL,
  `cust_email` varchar(250) DEFAULT NULL,
  `cust_pass` varchar(32) DEFAULT NULL,
  `cust_firstname` varchar(50) NOT NULL,
  `cust_surname` varchar(50) NOT NULL,
  `cust_address1` varchar(50) NOT NULL,
  `cust_address2` varchar(50) DEFAULT NULL,
  `cust_town` varchar(50) DEFAULT NULL,
  `cust_county` varchar(50) DEFAULT NULL,
  `cust_postcode` varchar(10) NOT NULL,
  `cust_phone` varchar(20) DEFAULT NULL,
  `cust_evephone` varchar(20) DEFAULT NULL,
  `cust_delpointid` int(11) DEFAULT NULL,
  `cust_notes` text NOT NULL,
  `cust_delnotes` text,
  `cust_delorder` int(10) NOT NULL DEFAULT '0',
  `cust_likes` text,
  `cust_dislikes` text,
  `cust_active` int(1) NOT NULL DEFAULT '1',
  `cust_auth` int(1) NOT NULL,
  `cust_newsletter` tinyint(4) NOT NULL DEFAULT '1',
  `cust_rep` varchar(250) DEFAULT NULL,
  `cust_join` datetime DEFAULT NULL,
  `cust_howheard` varchar(25) DEFAULT NULL,
  `cust_friendname` varchar(50) DEFAULT NULL,
  `cust_friend1staddress` varchar(50) DEFAULT NULL
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=18694 ;

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

--
-- Table structure for table `tbOrders`
--

CREATE TABLE IF NOT EXISTS `tbOrders` (
`order_id` int(11) NOT NULL,
  `order_custid` int(11) NOT NULL,
  `order_date` datetime NOT NULL,
  `order_status` int(1) NOT NULL,
  `order_exported` tinyint(1) NOT NULL DEFAULT '0',
  `order_subid` int(11) DEFAULT NULL,
  `discount_vouchers` longtext
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=310575 ;

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

--
-- Table structure for table `tbPayments`
--

CREATE TABLE IF NOT EXISTS `tbPayments` (
`pay_id` int(11) NOT NULL,
  `pay_custid` int(11) NOT NULL,
  `pay_date` datetime NOT NULL,
  `pay_value` float NOT NULL,
  `pay_detail` varchar(200) NOT NULL,
  `pay_stref` varchar(50) DEFAULT NULL,
  `pay_nomcode` int(5) NOT NULL,
  `pay_exported` tinyint(1) NOT NULL DEFAULT '0'
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=128264 ;

--
-- Indexes for dumped tables
--

--
-- Indexes for table `tbCustomers`
--
ALTER TABLE `tbCustomers`
 ADD PRIMARY KEY (`cust_id`), ADD KEY `cust_name` (`cust_firstname`,`cust_surname`), ADD KEY `cust_email` (`cust_email`), ADD KEY `cust_newsletter` (`cust_newsletter`);

--
-- Indexes for table `tbOrders`
--
ALTER TABLE `tbOrders`
 ADD PRIMARY KEY (`order_id`), ADD KEY `order_custid` (`order_custid`), ADD KEY `order_date` (`order_date`), ADD KEY `order_status` (`order_status`), ADD KEY `order_exported` (`order_exported`), ADD KEY `order_subid` (`order_subid`);

--
-- Indexes for table `tbPayments`
--
ALTER TABLE `tbPayments`
 ADD PRIMARY KEY (`pay_id`);

--
-- AUTO_INCREMENT for dumped tables
--

--
-- AUTO_INCREMENT for table `tbCustomers`
--
ALTER TABLE `tbCustomers`
MODIFY `cust_id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=18694;
--
-- AUTO_INCREMENT for table `tbOrders`
--
ALTER TABLE `tbOrders`
MODIFY `order_id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=310575;
--
-- AUTO_INCREMENT for table `tbPayments`
--
ALTER TABLE `tbPayments`
MODIFY `pay_id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=128264;

此外,在where子句中为错误的列名称道歉 - 现在修复

干杯!

1 个答案:

答案 0 :(得分:0)

我假设在WHERE子句中pay_custid应该替换为pay_date

将查询重写为:

SELECT DISTINCT c.cust_id 
  FROM tbCustomers AS c 
  JOIN tbOrders AS o 
    ON o.order_custid = c.cust_id 
  JOIN tbPayments AS p 
    ON p.pay_custid = c.cust_id 
 WHERE (
         o.order_date > CURDATE() - INTERVAL 14 DAY
     AND o.order_status = 3
     AND o.order_exported = 0
       ) 
    OR (
         p.pay_date > CURDATE() - INTERVAL 14 DAY) 
     AND p.pay_exported = 0
       )

这允许优化器在order_datepay_date上使用索引,如果它包含在DATE函数中,则无法使用索引。

我会在两个日期字段中添加索引,但每个表上的一个聪明的复合索引可能更灵活。

更好的可能是:

   SELECT DISTINCT c.cust_id 
     FROM tbCustomers AS c 
LEFT JOIN tbOrders AS o 
       ON o.order_custid = c.cust_id
      AND o.order_date > CURDATE() - INTERVAL 14 DAY
      AND o.order_status = 3
      AND o.order_exported = 0
LEFT JOIN tbPayments AS p 
       ON p.pay_custid = c.cust_id 
      AND p.pay_date > CURDATE() - INTERVAL 14 DAY) 
      AND p.pay_exported = 0
    WHERE (o.order_cust_id IS NOT NULL OR p.pay_cust_id IS NOT NULL)