Symfony2:使用flush()或persist()来优化数据处理

时间:2015-05-21 03:32:37

标签: php symfony

我正在使用Symfony(const version =" 2.5.10")并使用XAMPP和PHP版本5.5.19

我的问题是我继续出现内存不足错误。因为我认为我在数据库中查询了数千个数据(行)。有关信息,我在数据库中有很多数据。我想使用flush()或任何可用于优化数据处理的内容。

这是我的indexAction控制器中的代码:

public function indexAction(){
  $em = $this->getDoctrine()->getManager();
  $po = $em->getRepository('MatrixEdiBundle:EdiTransactionDetail')->findDocs('850');
  return $this->render('MatrixEdiBundle:Matrix:index.html.twig', array('po' => $po));
}

index.html.twig

{% extends '::layout.html.twig' %}
{# {% include 'MatrixEdiBundle:Matrix:header.html.twig'%} #}
{% block body %}
<div class="content">
</br>
  <table id="datTable"  class="table table-bordered table-condensed table-hover">
      <thead>
        <th colspan="8">Edi Matrix</th>
        <tr>
          <th>Po Numbers</th>
          <th>Trading Partner Id</th>
          <th>PO 855 Acknowledgement</th>
          <th>PO 997 Acknowledgement</th>
          <th>Advance Shipment Notice</th>
          <th>Invoice</th>
          <th>Purchase Order Change</th>
          <th>Order Status</th>
        </tr>
      </thead>
      <tbody>
      {% for tran in po %}
        <tr>
            <td><a href="{{ path('matrix_edi_showpo', {'po_num':  tran.poNumber}) }}"data-toggle="modal" data-target="#myModal">{{tran.poNumber}}</td>

            <td>{{tran.ediTransaction.senderId}}</td>

            <td><a href="{{ path('matrix_edi_findAll', {'po_num':  tran.poNumber, 'sender_id':  tran.ediTransaction.senderId, 'doc_type': 855}) }}"data-toggle="modal"data-target="#myModal">
            {{ render(controller('MatrixEdiBundle:Matrix:matrix', {
            'po_num': tran.poNumber, 'sender_id': tran.ediTransaction.senderId, 'reciever_id': tran.    ediTransaction.receiverId, 'doc_type': 855, 'gs_number': tran.ediTransaction.gsNumber })) }}</a>
            </td>

            <td><a href="{{ path('matrix_edi_poack', {'gs_number':  tran.ediTransaction.gsNumber, 'receiver_id':  tran.ediTransaction.receiverId, 'sender_id': tran.ediTransaction.senderId}) }}"data-toggle="modal"data-target="#myModal">
            {{ render(controller('MatrixEdiBundle:Matrix:matrix', {
            'po_num': tran.poNumber, 'sender_id': tran.ediTransaction.senderId, 'reciever_id': tran.    ediTransaction.receiverId, 'doc_type': 997, 'gs_number': tran.ediTransaction.gsNumber })) }}</a>
            </td>

            <td><a href="{{ path('matrix_edi_findAll', {'po_num':  tran.poNumber, 'sender_id':  tran.ediTransaction.senderId, 'doc_type': 856}) }}"data-toggle="modal"data-target="#myModal">{{ render(controller('MatrixEdiBundle:Matrix:matrix', {
            'po_num': tran.poNumber, 'sender_id': tran.ediTransaction.senderId, 'reciever_id': tran.ediTransaction.receiverId, 'doc_type': 856, 'gs_number': tran.ediTransaction.gsNumber }))}}</a>
            </td>

            <td><a href="{{ path('matrix_edi_findAll', {'po_num':  tran.poNumber, 'sender_id':  tran.ediTransaction.senderId, 'doc_type': 810}) }}"data-toggle="modal"data-target="#myModal">{{ render(controller('MatrixEdiBundle:Matrix:matrix', {'po_num': tran.poNumber, 'sender_id': tran.ediTransaction.senderId, 'reciever_id': tran.ediTransaction.receiverId, 'doc_type': 810, 'gs_number': tran.ediTransaction.gsNumber})) }}</a>
            </td>

            <td><a href="{{ path('matrix_edi_findAll', {'po_num':  tran.poNumber, 'sender_id':  tran.ediTransaction.senderId, 'doc_type': 860}) }}"data-toggle="modal"data-target="#myModal">{{ render(controller('MatrixEdiBundle:Matrix:matrix', {'po_num': tran.poNumber, 'sender_id': tran.ediTransaction.senderId, 'reciever_id': tran.ediTransaction.receiverId, 'doc_type':860, 'gs_number': tran.ediTransaction.gsNumber})) }}</a>
            </td>

          <td><a href="{{ path('matrix_edi_findAll', {'po_num':  tran.poNumber, 'sender_id':  tran.ediTransaction.senderId, 'doc_type': 870}) }}"data-toggle="modal"data-target="#myModal">{{ render(controller('MatrixEdiBundle:Matrix:matrix', {
        'po_num': tran.poNumber, 'sender_id': tran.ediTransaction.senderId, 'reciever_id': tran.ediTransaction.receiverId, 'doc_type': 870, 'gs_number': tran.ediTransaction.gsNumber
    })) }}</a></td>

        </tr>
      {% endfor %}
    </tbody>
    </table>
  </div> 


<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="false" >
    <div class="modal-dialog">
        <div class="modal-content" style="width: 650px;">
            <div class="modal-header" style="background-color: #2d6ca2; color: white;">
                <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true" style="color: white;">×</span><span class="sr-only">Close</span></button>
                <h4 class="modal-title" id="myModalLabel" >Details</h4>
            </div>
      <div class="modal-body">
          Loading, please wait......
          <div class="bootstrap-table">

              <div class="fixed-table-container" style="height: 299px; padding-bottom: 37px;">
                <div class="fixed-table-body">
                  <div class="fixed-table-loading" style="top: 27px; display: none;">Loading, please wait…</div>
                </div>
                <div class="fixed-table-pagination"></div>
              </div>
          </div><div class="clearfix"></div>
      </div>  

      <div class="modal-footer">
          <button type="button" class="btn btn-primary" data-dismiss="modal" >Close</button>
      </div>
    </div><!-- /.modal-content -->
  </div><!-- /.modal-dialog -->
</div><!-- /.modal -->
{% endblock %}

{% block javascripts %}
{% javascripts
  'bundles/matrixdoc/js/jQuery.js'
  'bundles/matrixdoc/js/jquery.dataTables.min.js'
  'bundles/matrixdoc/js/dataTables.bootstrap.js'
  'bundles/matrixdoc/js/bootstrap.js'
   %}
  <script src="{{ asset_url }}"></script>
  <script type="text/javascript">
  $(document).ready(function() {
    $('#datTable').dataTable( {
      "scrollY": "400px",
      "scrollCollapse": true,
      "pagingType": "simple",
    });
    $('body').on('hidden.bs.modal', '.modal', function () {
      $(this).removeData('bs.modal');
    });
    $(document).on("hidden.bs.modal", function (e) {
      $(e.target).removeData("bs.modal").find(".modal-content").empty();
    });
    });
</script>
{% endjavascripts %}
{% endblock %}

1 个答案:

答案 0 :(得分:2)

如果你不需要所有东西,你应该使用分页来获取有限的数据,并使用partial来获取你需要的字段。

http://zrashwani.com/pagination-optimization-symfony2-doctrine/#.VV1av_mSwbg

对于DQL中的部分,用户的简单示例:

//partial_fields is an array, which can be passed like this $repo->getPartialUser($user_id, array('field1', 'field2', 'etc..');
    public function getPartialUser($id, $partial_fields){
        $qb = $this->_em->createQueryBuilder()
            ->select('partial u.{'.implode(',',$partial_fields).'}')
            ->from('AcmeUserBundle:User', 'u')
            ->where('u.id = :id')
            ->setParameter('id', $id);
        $result = $qb->getQuery()->getOneOrNullResult();
        return $result;
    }

编辑示例代码:

我会给你一个例子,但你可能仍然需要让它适应你的代码,或者它可以开箱即用。

首先你需要一个新的树枝和简单的代码来显示表格下方导航的页码(请注意,我不会使用数据表的分页符,但我们将保留它用于表格布局渲染):

pager.html.twig

<div class="pagination">
    <div class="pagination-buttons">
        {% if pagination.page>1 %}
            <a href="{{ path(pagination.route,
            pagination.route_params|merge({'page': 1})) }}"><<</a>
            <a href="{{ path(pagination.route,
            pagination.route_params|merge({'page': pagination.page-1})) }}"><</a>
        {% endif %}
        {#display p numbers only from p-4 to p+4 but don't go <1 or >pages_count#}
        {% for p in range(max(pagination.page-4, 1),
        min(pagination.page+4, pagination.pages_count)) %}
            <a{% if p == pagination.page %} class="current-page"{% endif %}
                    href="{{ path(pagination.route,
                    pagination.route_params|merge({'page': p})) }}">{{ p }}</a>
        {% endfor %}
        {% if pagination.page<pagination.pages_count %}
            <a href="{{ path(pagination.route,
            pagination.route_params|merge({'page': pagination.page+1})) }}">></a>
            <a href="{{ path(pagination.route,
            pagination.route_params|merge({'page': pagination.pages_count})) }}">>></a>
        {% endif %}
    </div>
</div>

EdiTransactionDetailRepository:

为您在表格中使用的字段添加一个函数:

public function  getPagedDocs($page = 1, $limit = 50)
    {
        $qb = $this->_em->createQueryBuilder()
             ->select('partial d.{field1,field2 , etc..},
                       partial et.{field1,field2, etc..}'
              ))//select doc fields and second partial for your join select edittransaction fields if you have other joins add another partial etc.. 
             ->from('YourBundle:DocsEntity', 'd')
             ->innerJoin('d.ediTransaction', 'et')//not sure which join you need i have no clue but i believe you will want an inner one since you will want a doc to have a ediTransaction because i didn't see any checks in your twig for it if null.
             ->setFirstResult(($page - 1) * $limit)
             ->setMaxResults($limit);

        $paginator =  new Paginator($qb, $fetchJoinCollection = false);//for more performance fetchjoincollection to false if you have joined tables
        $paginator->setUseOutputWalkers(false);//for more performance set to false for more information http://www.doctrine-project.org/jira/browse/DDC-2890

        return $paginator;
    }

PS:将每个页面中要显示的记录数限制更改,具体取决于数据的负载,如果速度低50,则取决于每行的数据量。

接下来是控制器中的indexAction:

public function indexAction($page){
  $em = $this->getDoctrine()->getManager();
  $po = $em->getRepository('MatrixEdiBundle:EdiTransactionDetail')->getPagedDocs($page, 50);
  $count = $po->count();
  $pagination = array(
        'page' => $page,
        'route' => 'docs_index_route_name', //i dont know which name you have but it should be the route name of this indexAction
        'route_params' => array()
    );
    if ($max_records > 0)
        $pagination['pages_count'] = max(ceil($count / $max_records), 1);
  return $this->render('MatrixEdiBundle:Matrix:index.html.twig', array('po' => $po,
  'pagination' => $pagination
    ));
}

路由:

您需要修改indexAction的路由,因为我们添加了一个参数页面,您需要为路径添加它:

index_docs:
    pattern:  /index/{page}
    defaults: { _controller: "YourBundle:Controller:index", page: 1 }

注意:您需要更改名称和内容我不知道您的控制器名称和包,所以通常您只需要将/ {page}添加到模式中,并且页面:1到您的_controller配置这是默认的值。

最后要做的是你的index.html.twig需要包含我们的pager.html.twig

关闭桌子后包含这段代码:

    {% if po|length > 0  and pagination['pages_count'] is defined and pagination['pages_count'] > 0 %}
        {#---------Pager----------#}
        <div style="text-align:center;">
            {% include 'YourBundle:EntityDoc:pager.html.twig' %}
        </div>
    {% endif %}

注意:include是您创建pager.html.twig的文件的路径。我假设您熟悉其工作原理。

因此,如果我没有忘记任何事情,这应该开箱即用,它应该大大提高你的性能,但我担心你的每一行的渲染控制器可能仍然有问题。但首先尝试这个解决方案,看看,这取决于你放在那些控制器中的内容。