对于循环和太多循环使执行时间更长?

时间:2017-07-29 05:27:03

标签: php performance symfony processing-efficiency

我目前正面临一场噩梦。我的数据库几乎只有 400条记录,问题在于我的PHP代码正在生成图像滑块,所以代码就像 60秒几乎只执行 400记录这是太多的时间,没有人能忍受等待那么多时间。 我真的很担心,因为我不知道可以做些什么才能让它更快但据我所知,通过使用foreach循环代替for循环可以让事情变得更快但我想知道你是否有人可以讨好为我提供解决方案。

它是Symfony网站内的部分模板,它呈现图像滑块并从数据库中获取每个图像的滑块。但是我并不担心SQL查询,因为执行所有查询以获取这些滑块图像最多只需要 3到4秒,但生成滑块的代码需要很多在大多数情况下,大多数时间几乎 60+秒,这对于任何人来说都是太长时间了。

如果您能为我提供最佳性能的优化代码,我将不胜感激。

这里的统计数据为: enter image description here

enter image description here 这是我的代码(_ searchResults.php)

<?php if (count($locations) > 0): ?>
  <?php foreach ($locations as $location): ?>
    <?php if ($location->PhotoFiles->count()): ?>
      <li class="item" data-location-id="<?php echo $location->id ?>">
        <div class="searchItemSlider">
          <?php $limit = ($location->PhotoFiles->count() >= 10 ? 10 : $location->PhotoFiles->count()); ?>
          <?php for ($i = 1; $i < ($limit + 1); $i++): ?>
            <?php $photo = $location->findPhotoIndex($i); ?>
            <?php //if (1): ?>
            <?php  if ($photo && $thumb = $photo->getThumbnailByType(ThumbnailTable::THUMB_520_392)): ?>
              <div class="searchItem">
                <figure>
                  <?php  if (file_exists($thumb->getFullFilesystemPath())): ?>
                    <?php //if (1 == 2): ?>
                    <div class="thumb-img">
                      <img class="lazyOwl" src="<?php echo $thumb->getFullWebPath() ?>" />
                    </div>
                  <?php else: ?>
                    <div class="thumb-img">
                      <img class="lazyOwl" src="/images/newfrontend/categories/no_venue.jpg" />
                    </div>
                  <?php endif; ?>
                  <figcaption>
                    <a href="<?= url_for("@venue_details?id=" . $location->id) ?>" title="<?php echo $location->venue_name; ?>"><?php echo $location->venue_name; ?></a>
                    <br />
                  </figcaption>
                  <?php $districtName = (strlen($location->venue_area)) ? $location->venue_area : $location->getGeoLocationDistrictName();
                    if (strlen($districtName)): ?>
                    <div class="district_name"><a href="<?= url_for("@venue_details?id=" . $location->id) ?>" title="<?php echo $location->venue_name; ?>"><?php echo $districtName ?></a></div>
                  <?php endif; ?>
                </figure>
                <p><?php echo substr(strip_tags(html_entity_decode($location->description)), 0, 100) ?></p>
                <span class="eye"><a href="<?= url_for("@venue_details?id=" . $location->id) ?>" title="<?php echo $location->venue_name; ?>"><img src="/images/newfrontend/icons/eye-icon.png"/></a></span>

                <div class="links">                  
                  <a href="<?php echo url_for('@venue_share?id=' . $location->id) ?>" class="arrow share_links" data-toggle="tooltip" title="Share this venue">&nbsp;</a>
                  <?php if (!$sf_user->locationInWishlist($location->id)): ?>
                    <a href="<?php echo url_for('@wishlist_addtowishlistajaxraw') ?>" data-attr-venue-id="<?php echo $location->id ?>" class="pin add_to_wishlist" data-toggle="tooltip" title="Add to wishlist">&nbsp;</a>
                  <?php else: ?>
                    <a href="javascript:void(0)" class="added-to-wishlist">&nbsp;</a>
          <?php endif; ?>
                </div>
              </div>
            <?php endif; ?>
      <?php endfor; ?>
        </div>
      </li>
    <?php else: ?>
      <li class="item" data-location-id="<?php echo $location->id ?>">
        <div class="searchItemSlider">
          <div class="searchItem">
            <figure>
              <div class="thumb-img">
                <img class="lazyOwl" src="/images/newfrontend/categories/no_venue.jpg" />
              </div>
              <figcaption>
                <a href="<?= url_for("@venue_details?id=" . $location->id) ?>" title="<?php echo $location->venue_name; ?>"><?php echo $location->venue_name; ?></a>
                <br />
              </figcaption>
              <?php $districtName = (strlen($location->venue_area)) ? $location->venue_area : $location->getGeoLocationDistrictName();

              if (strlen($districtName)):
                ?>
              <div class="district_name"><a href="<?= url_for("@venue_details?id=" . $location->id) ?>" title="<?php echo $location->venue_name; ?>"><?php echo $districtName ?></a></div>
              <?php endif; ?>
            </figure>
            <p><?php echo substr(strip_tags(html_entity_decode($location->description)), 0, 100) ?></p>
            <span class="eye"><a href="<?= url_for("@venue_details?id=" . $location->id) ?>" title="<?php echo $location->venue_name; ?>"><img src="/images/newfrontend/icons/eye-icon.png"/></a></span>

            <div class="links">                  
              <a href="<?php echo url_for('@venue_share?id=' . $location->id) ?>" class="arrow share_links" title="Share this venue">&nbsp;</a>
              <?php if (!$sf_user->locationInWishlist($location->id)): ?>
                <a href="<?php echo url_for('@wishlist_addtowishlistajaxraw') ?>" data-attr-venue-id="<?php echo $location->id ?>" class="pin add_to_wishlist" data-toggle="tooltip" title="Add to wishlist">&nbsp;</a>
              <?php else: ?>
                <a href="javascript:void(0)" class="added-to-wishlist">&nbsp;</a>
              <?php endif; ?>
            </div>
          </div>
        </div>
      </li>
    <?php endif; ?>
  <?php endforeach; ?>
<?php endif; ?>

更新:

位置: /lib/model/doctrine/PhotoFile.class.php

  /**
   * Returns the first thumbnail of a certain type
   * or false if no thumbnail matches
   *
   * @param const $type The type of thumbnail, from the ThumbnailTable::THUMB_* constants
   * @return bool|Thumbnail
   */
  public function getThumbnailByType($type) {
    foreach ($this->Thumbnails as $t) {
      if ($t->thumb_type == $type) {
        return $t;
      }
    }
    return false;
  }

位置: /lib/model/doctrine/Location.class.php

   /**
   * Geocoder: get district name (administrative county)
   *
   * @return string
   */
  public function getDistrictName()
  {
    return ($this->hasGeocode() ? $this->getGeocode()->district_name : null);
  }

  public function getGeoLocationDistrictName()
  {
    $districtName = '';
    if($this->getGeocoded()->count() > 0)
    {
      if($this->getGeocoded()->getFirst()->getGeolocationPostcode()->count() > 0)
      {
        if($this->getGeocoded()->getFirst()->getGeolocationPostcode()->getFirst()->getGeolocationDistrict()->count() > 0)
        {
          $districtName = $this->getGeocoded()->getFirst()->getGeolocationPostcode()->getFirst()->getGeolocationDistrict()->getFirst()->getName();
        }
      }
    }
    return $districtName;
  }

 /**
   * Gets the geocode data for this location.
   * We store it locally so we don't need to keep querying for it.
   *
   * @return boolean|PcawCodes $pcawCode
   */
  public function getGeocode()
  {
    if ($this->Geocoded->count())
    {
      return $this->Geocoded->getFirst();
    }

    if (!strlen($this->address_postcode))
    {
      // No postcode to geocode
      return false;
    }

    $geocode = new JointGeocoder();
    try
    {
      /* @var $result PcawCodes */
      $result = $geocode->geocode("", $this->address_postcode);

      // Add the postcode also to the GeolocationPostcode table
      if($result) Doctrine::getTable('GeolocationPostcode')->addPostcodeIfMissing($result);
    }
    catch (Exception $e)
    {
      // Some problem occurred geocoding, return false
      return false;
    }

    return $result;
  }

2 个答案:

答案 0 :(得分:2)

我注意到您使用的基准测试工具似乎表明该页面正在进行4540次查询。如果是这样可能是原因。

根据你的代码,我怀疑这是n + 1问题 - 实际上是通过单独获取一个新模型在循环中进行另一个查询。大多数ORM都有一种机制可以通过预先加载来解决这个问题,因此它们会事先获取所有这些行。使用预先加载也可以更容易地缓存响应。

我不熟悉Doctrine,但根据https://tideways.io/profiler/blog/5-doctrine-orm-performance-traps-you-should-avoid它支持急切加载。

答案 1 :(得分:1)

我不打算具体告诉您如何解决这个问题,而是提出改进性能的建议。

  1. 您的查询完成3到4秒是一个很长的时间。优化数据库模式,分析查询,使用适当的索引。

  2. 仅查询您需要的数据。如果您不需要400个结果,请适当地限制您的查询。

  3. 这些数据多久更改一次?它总是需要是最新的吗?将数据解析为控制器或服务类中所需的结构,然后将其缓存到文件或类似文件中。

  4. 读取缓存的数据,而不是每次都访问数据库。

  5. 不要动态或在需要时生成缩略图。在上传时生成它们,或者生成它们并将其缓存以备将来使用。

  6. 构建视图并缓存视图,以便每次都不再访问数据库。

  7. 使用适当的缓存标头提供您的内容,以便用户的浏览器缓存页面和/或资源。