Doctrine / MySQL即使使用索引也慢速查询

问题描述 投票:0回答:2

我整理了一下问题,因为它变得很大且难以理解。

正如您在下面的图像中所看到的,当从包含15000行(条件返回6650的where的表)中选择表时,查询将使用755.15 ms

表Company,包含1000行。表geo__name包含84300行aprox,并且没有给我任何问题,因此我认为问题是数据库结构或其他问题。

这两个表的结构如下:

表作业为:

CREATE TABLE `job` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL,
  `company_id` int(11) NOT NULL,
  `activity_sector_id` int(11) DEFAULT NULL,
  `status` int(11) NOT NULL,
  `active` datetime NOT NULL,
  `contract_type_id` int(11) NOT NULL,
  `salary_type_id` int(11) NOT NULL,
  `workday_id` int(11) NOT NULL,
  `geoname_id` int(11) NOT NULL,
  `title` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `minimum_experience` int(11) DEFAULT NULL,
  `min_salary` decimal(7,2) DEFAULT NULL,
  `max_salary` decimal(7,2) DEFAULT NULL,
  `zip_code` int(11) DEFAULT NULL,
  `vacancies` int(11) DEFAULT NULL,
  `show_salary` tinyint(1) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `created_at` (`created_at`,`active`,`status`) USING BTREE,
  CONSTRAINT `FK_FBD8E0F823F5422B` FOREIGN KEY (`geoname_id`) REFERENCES `geo__name` (`id`),
  CONSTRAINT `FK_FBD8E0F8398DEFD0` FOREIGN KEY (`activity_sector_id`) REFERENCES `activity_sector` (`id`),
  CONSTRAINT `FK_FBD8E0F85248165F` FOREIGN KEY (`salary_type_id`) REFERENCES `job_salary_type` (`id`),
  CONSTRAINT `FK_FBD8E0F8979B1AD6` FOREIGN KEY (`company_id`) REFERENCES `company` (`id`),
  CONSTRAINT `FK_FBD8E0F8AB01D695` FOREIGN KEY (`workday_id`) REFERENCES `workday` (`id`),
  CONSTRAINT `FK_FBD8E0F8CD1DF15B` FOREIGN KEY (`contract_type_id`) REFERENCES `job_contract_type` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=15001 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

餐桌公司是:

CREATE TABLE `company` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `logo` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL,
  `website` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `user_id` int(11) NOT NULL,
  `phone` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `cifnif` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `type` int(11) NOT NULL,
  `subscription_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `UNIQ_4FBF094FA76ED395` (`user_id`),
  KEY `IDX_4FBF094F9A1887DC` (`subscription_id`),
  KEY `name` (`name`(191)),
  CONSTRAINT `FK_4FBF094F9A1887DC` FOREIGN KEY (`subscription_id`) REFERENCES `subscription` (`id`),
  CONSTRAINT `FK_4FBF094FA76ED395` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1001 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

查询如下:

SELECT 
  j0_.id AS id_0, 
  j0_.status AS status_1, 
  j0_.title AS title_2, 
  j0_.min_salary AS min_salary_3, 
  j0_.max_salary AS max_salary_4, 
  c1_.id AS id_5, 
  c1_.name AS name_6, 
  c1_.logo AS logo_7, 
  a2_.id AS id_8, 
  a2_.name AS name_9, 
  g3_.id AS id_10, 
  g3_.name AS name_11, 
  j4_.id AS id_12, 
  j4_.name AS name_13, 
  j5_.id AS id_14, 
  j5_.name AS name_15, 
  w6_.id AS id_16, 
  w6_.name AS name_17 
FROM 
  job j0_ 
  INNER JOIN company c1_ ON j0_.company_id = c1_.id 
  INNER JOIN activity_sector a2_ ON j0_.activity_sector_id = a2_.id 
  INNER JOIN geo__name g3_ ON j0_.geoname_id = g3_.id 
  INNER JOIN job_salary_type j4_ ON j0_.salary_type_id = j4_.id 
  INNER JOIN job_contract_type j5_ ON j0_.contract_type_id = j5_.id 
  INNER JOIN workday w6_ ON j0_.workday_id = w6_.id 
WHERE 
  j0_.active >= CURRENT_TIMESTAMP 
  AND j0_.status = 1 
ORDER BY 
  j0_.created_at DESC

执行上述查询时,我得到以下结果:

在MYSQL工作台中:0.578 sec / 0.016 sec在Symfony探查器中:755.15 ms

问题是:此查询的持续时间是否正确?如果没有,如何提高查询速度?似乎很多。

enter image description here

symfony调试工具栏,如果有帮助:

enter image description here

php mysql symfony doctrine symfony4
2个回答
0
投票

键太多,请尽量减少键的数量。


0
投票

Symfony速度缓慢的原因有很多。

1。服务器故障

首先,这可能是服务器故障。服务器性能可能会影响您的查询时间。

2。数据大小和延迟渲染

然后是数据大小。如下图所示,我的一个项目的查询的数据大小为50Mb(当前约2万行)。在HTML中解析50Mb可能需要一些时间,这主要是因为循环。仍然有关于此的解决方案,例如延迟渲染。

enter image description here

延迟渲染非常简单,您无需解析树枝中的数据,将所有数据发送到javascript变量,并在加载DOM后使用javascript解析/呈现数据。

3。查询优化

正如我在评论中写道,您可以检查以下问题,在该问题上,我解释了为什么自定义查询很重要。Are Doctrine relations affecting application performance?

在这个问题上,您将阅读该顺序的问题……实际上,这是最重要的。

虽然数据库中的静态数据通常以正确的顺序插入,动态数据(用户在网站生命期间提供的数据)很少出现这种情况]

这就是为什么在查询中使用ORDER BY通常会加快页面呈现的速度,因为教义本身不会做额外的查询。

例如,我的一个站点在索引上显示了约700个条目。首先,这是使用findAll()时的查询计数:

enter image description here

它在144毫秒内显示254个查询(253个重复项),外加39个渲染时间。接下来,使用findBy()的第二个参数ORDER BY,我得到以下结果:

enter image description here

您可以看到full query here(镜头很大)更好的是,仅在8毫秒内进行1次查询,并且渲染时间大致相同。但是,在这里,我不使用关联中的任何字段。从我要做的那一刻起,doctrine qui会做一些额外的查询,并且查询数量和时间将猛增。最后,它将回到类似findAll()

的位置

最后,这是自定义查询:

enter image description here

在此custom query中,查询时间从8ms变为38ms。但是,与之前的查询不同,我在查询结果中获得了更多数据,这将阻止教义进行额外的查询。同样,ORDER BY()在此查询中很重要。没有它,我将猛增回84个查询。

4。局部]

当您执行自定义查询时,您可以加载部分对象而不是全部数据。就像您在问题中说的那样,description字段似乎减慢了您的加载速度,使用局部函数,可以避免从表中加载某些字段,这将加快查询速度。

首先,这是您创建查询生成器的方式,而不是常规语法:

$em=$this->getEntityManager();
$qb=$em->createQueryBuilder();

以防万一,我更愿意将$em保留为单独的变量(例如,如果我想获取某些类存储库)。

然后您可以启动部分select。请注意,第一个select不能包含任何关联字段:

$qb->select("partial job.{id, status, title, minimum_experience, min_salary, max_salary, zip_code, vacancies")
   ->from(Job::class, "job");

然后您可以添加关联:

$qb->addSelect("company")
   ->join("job.company", "company");

甚至在不需要所有关联数据的情况下,甚至添加部分关联:

$qb->addSelect("partial activitySector.{id}")
   ->join("job.activitySector", "activitySector");

$qb->addSelect("partial job.{id, company_id, activity_sector_id, status, active, contract_type_id, salary_type_id, workday_id, geoname_id, title, minimum_experience, min_salary, max_salary, zip_code, vacancies, show_salary");

5。缓存

您还可以使用各种缓存,例如Zend OPCache for PHP,您可以在此问题中找到一些建议:Why Symfony3 so slow?

还有SQL缓存Varnish。


本文汇总了我可以共享的所有内容,以减少您的加载时间。

希望它将证明是有用的,您将能够解决您的问题。

© www.soinside.com 2019 - 2024. All rights reserved.