【发布时间】:2018-05-13 23:06:20
【问题描述】:
此 select 语句运行速度非常慢。完成执行需要 10 多秒。可能会更长,但我不知道,因为与 MySQL 的连接超时。这是一个单独的问题。
代码如下:
SELECT
f.id, f.name, GROUP_CONCAT(DISTINCT (c.firstname)) children
FROM
families f,
children c,
transactions t
WHERE
f.companyid = 1170 AND f.id = t.familyid
AND f.id = c.familyid
AND t.transactiontype = 'P'
AND t.taxdeductible = 'Y'
AND YEAR(t.date) = 2017
AND status = 'A'
OR f.id = 9779432
GROUP BY f.id
ORDER BY name;
我确实有有关family.companyid、children.familyid、transactions.transactiontype、transactions.taxdeductible 和transactions.date 的索引。
尽管有我的索引,它是否有任何理由进行全表扫描?还是有其他原因导致此查询运行缓慢?
编辑:按照以下 cmets 填写一些空白:
儿童桌
CREATE TABLE `children` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`familyid` int(10) unsigned DEFAULT '0',
`companyid` int(11) DEFAULT '0',
`picture` varchar(250) DEFAULT NULL,
`stockpicture` varchar(1) DEFAULT 'N',
`firstname` varchar(250) DEFAULT NULL,
`lastname` varchar(250) DEFAULT NULL,
`nickname` varbinary(250) DEFAULT NULL,
`birthdate` date NOT NULL DEFAULT '0000-00-00',
`usecustomfee` varchar(1) NOT NULL DEFAULT 'N',
`usecustomproviderfee` varchar(1) NOT NULL DEFAULT 'N',
`customfee` decimal(10,2) DEFAULT '0.00',
`customfeetypecode` varchar(45) DEFAULT 'MONTH',
`customproviderfee` decimal(10,2) DEFAULT '0.00',
`customproviderfeetypecode` varchar(45) DEFAULT 'MONTH',
`usecustomchargeitem` varchar(1) DEFAULT 'N',
`customchargeitem` int(11) DEFAULT '0',
`dailyrate` decimal(10,2) DEFAULT '55.00',
`startdate` date DEFAULT NULL,
`enddate` date DEFAULT NULL,
`subsidynotrequired` char(1) NOT NULL DEFAULT 'Y',
`subsidychildid` varchar(250) DEFAULT NULL,
`subsidyapplicantid` varchar(250) DEFAULT NULL,
`subsidynote` text,
`waitingsince` date DEFAULT NULL,
`waitingroom` int(11) DEFAULT NULL,
`waitingtype` varchar(1) DEFAULT 'F',
`preferredstart` date DEFAULT NULL,
`registrationdate` date DEFAULT NULL,
`groupid` int(11) NOT NULL DEFAULT '0',
`providerisparent` varchar(1) NOT NULL DEFAULT 'N',
`attendingschool` char(1) NOT NULL DEFAULT 'N',
`schoolname` varchar(250) DEFAULT NULL,
`liveswithmother` char(1) NOT NULL DEFAULT 'Y',
`liveswithfather` char(1) NOT NULL DEFAULT 'Y',
`liveswithother` char(1) NOT NULL DEFAULT 'N',
`otherguardian` varchar(250) DEFAULT NULL,
`sex` char(1) NOT NULL DEFAULT 'M',
`note` text,
`archived` char(1) NOT NULL DEFAULT 'N',
`priorityid` int(11) DEFAULT '0',
`onlineregistration` varchar(1) NOT NULL DEFAULT 'N',
`onlineregistrationaccept` varchar(1) NOT NULL DEFAULT 'N',
`registrationconfirmed` varchar(1) NOT NULL DEFAULT 'N',
`registrationconfirmeddate` datetime DEFAULT NULL,
`createddate` datetime DEFAULT NULL,
`modifieddate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`fullpart` varchar(1) DEFAULT 'F',
`parttimedays` int(11) DEFAULT '10',
`parttimedaystype` varchar(45) DEFAULT 'D',
`parttimedaystypecode` varchar(45) DEFAULT 'MONTH',
`program` varchar(45) DEFAULT 'daycare',
`registrationnote` varchar(2000) DEFAULT NULL,
`registrationnoteread` varchar(1) DEFAULT 'N',
`registrationsubsidy` varchar(45) DEFAULT 'noplan',
`registrationsubsidydate` datetime DEFAULT NULL,
`registrationsubsidyamount` decimal(10,2) DEFAULT '0.00',
PRIMARY KEY (`id`),
KEY `Familyid` (`familyid`),
KEY `companyid` (`companyid`),
KEY `startdate` (`startdate`),
KEY `enddate` (`enddate`),
KEY `roomid` (`groupid`),
KEY `providerisparent` (`providerisparent`)
) ENGINE=InnoDB AUTO_INCREMENT=93685 DEFAULT CHARSET=latin1;
家庭表
CREATE TABLE `families` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`accountnumber` varchar(100) DEFAULT NULL,
`name` varchar(245) NOT NULL COMMENT 'The account name will typically be the name of the parent responsible for payment',
`motherid` int(10) unsigned NOT NULL,
`fatherid` int(10) unsigned NOT NULL,
`balance` decimal(10,2) NOT NULL DEFAULT '0.00',
`notes` varchar(2000) DEFAULT NULL,
`companyid` int(10) unsigned NOT NULL,
`status` varchar(1) NOT NULL DEFAULT 'A',
`financialaidrequired` char(1) NOT NULL DEFAULT 'N',
`intakesurveyid` int(10) unsigned DEFAULT NULL,
`referralid` int(10) unsigned NOT NULL DEFAULT '0',
`registrationemailrequired` varchar(1) DEFAULT 'N',
`registrationemailsent` varchar(1) DEFAULT 'N',
`registrationemaildate` date DEFAULT NULL,
`registrationemailaddressfound` varchar(1) DEFAULT NULL,
`waitinglistemailrequired` varchar(1) DEFAULT 'N',
`waitinglistemailsent` varchar(1) DEFAULT 'N',
`waitinglistemaildate` date DEFAULT NULL,
`waitinglistemailaddressfound` varchar(1) DEFAULT NULL,
`activationemailrequired` varchar(1) DEFAULT 'N',
`activationemailsent` varchar(1) DEFAULT 'N',
`activationemaildate` date DEFAULT NULL,
`activationemailaddressfound` varchar(1) DEFAULT NULL,
`createddate` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `companyid` (`companyid`),
KEY `intakesurveyid` (`intakesurveyid`),
KEY `status` (`status`)
) ENGINE=InnoDB AUTO_INCREMENT=9803007 DEFAULT CHARSET=latin1;
交易表
CREATE TABLE `transactions` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`familyid` int(10) unsigned NOT NULL,
`date` datetime NOT NULL,
`transactiontype` varchar(1) NOT NULL DEFAULT 'C' COMMENT '''C'' = Charge, ''P'' = Payment',
`paymenttype` varchar(3) DEFAULT NULL COMMENT '''DBT'' = Debit, ''CSH'' = Cash, ''CRE'' = Credit Card, ''CHQ'' = Cheque, ''MNY'' = Money Order,''EFT'' = Electronic Funds Transfer',
`comment` varchar(500) DEFAULT NULL,
`amount` decimal(10,2) NOT NULL DEFAULT '0.00',
`reference` varchar(45) DEFAULT NULL,
`chargeitem` int(10) unsigned DEFAULT '0',
`taxdeductible` varchar(1) NOT NULL DEFAULT 'Y',
`payer` varchar(1) DEFAULT 'M',
`createddate` datetime DEFAULT NULL,
`modifieddate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `Familyid` (`familyid`),
KEY `Transaction Type` (`transactiontype`),
KEY `Tax Deductible` (`taxdeductible`),
KEY `date` (`date`)
) ENGINE=InnoDB AUTO_INCREMENT=1013472 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC;
【问题讨论】:
-
1) 你在这里跑题了;请参阅 DBA 网站 2)您没有提供足够的信息;例如你的表的体积(对于小表,从不使用索引) 3)“我失去了我的连接 mysql”看起来是一个完全不同的问题,应该首先解决 4)加上括号,因为 X AND Y OR Z 读起来不明确,确保它做你想做的事。 4) 在表之间使用正确的 SQL 语法和 INNER JOIN
-
关于查询性能的问题总是需要针对所有相关的 SHOW CREATE TABLE 语句以及 EXPLAIN 的结果。另外,请注意
YEAR(t.date) = 2017不能使用索引,但t.date BETWEEN '2017-01-01' AND '2017-12-31'可以。 -
您没有提供足够的信息让我们帮助您。请read this note about asking good SQL questions,并关注查询性能部分。那么请edit你的问题。
-
@PatrickMevzek - “失去连接”通常意味着查询运行时间过长。因此,这个是正确的论坛。 (当然,OP 不知道这一点。)
-
@PatrickMevzek - 我将优化视为 SE 和 SO 之间的灰色区域。我说“正确”的解决方案不会通过配置。我对程序员编写草率代码的公司感到恼火,然后将其扔给因需要重新编写查询而流泪的DBA。这个特定的问题大部分由程序员解决。