JdbcDaoSupport queryForList slow

时间:2015-07-25 07:12:13

标签: java mysql spring

我试图使用spring框架JdbcDaoSupport创建一个简单的servlet来显示数据库中的一些数据。执行一个" SELECT" -sql命令大约需要25-35秒。我是春天的新手,我不知道为什么这需要这么久......

这是我的代码: BeanBox.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:c="http://www.springframework.org/schema/c"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:lang="http://www.springframework.org/schema/lang"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:util="http://www.springframework.org/schema/util"

       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
          http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
          http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
          http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.2.xsd
          http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
          http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd
">

        <!-- Data access related beans-->
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location">
            <value>Settings.properties</value>
        </property>
    </bean>

    <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${db.driverClassName}" />
        <property name="url" value="${db.url}" />
        <property name="username" value="${db.user}" />
        <property name="password" value="${db.password}" />
        <property name="initialSize" value="8" />
    </bean>

    <bean id="productAnalyticsDAO" class="productAnalyticsDAO">
        <property name="dataSource" ref="dataSource" />
    </bean>

</beans>

products.java(实际的servlet)

public class products extends HttpServlet {

    /**
     * Processes requests for both HTTP <code>GET</code> and <code>POST</code>
     * methods.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        System.out.println("start:" + System.nanoTime());

        response.setContentType("text/html;charset=UTF-8");
        ApplicationContext context = new ClassPathXmlApplicationContext("BeanBox.xml");

        System.out.println("context created from xml:" + System.nanoTime());
        productAnalyticsDAO productDAO  = (productAnalyticsDAO) context.getBean("productAnalyticsDAO");

        System.out.println("getbean for the DAO:" + System.nanoTime());
        String interval = request.getParameterMap().isEmpty()? "today" : request.getParameter("t");

        System.out.println("fetch time parameter from request:" + System.nanoTime());

        try (PrintWriter out = response.getWriter()) {
            /* TODO output your page here. You may use following sample code. */
            out.println("<!DOCTYPE html>");
            out.println("<html>");
            out.println("<head>");
            out.println("<title>Servlet products</title>");            
            out.println("</head>");
            out.println("<body>");
            out.println("<h1>Product analytics : " + interval.toUpperCase() + "</h1>");
            out.println("<a href=\"products?t=today\">Today</a>, ");
            out.println("<a href=\"products?t=1D\">Yesterday</a>, ");
            out.println("<a href=\"products?t=WEEKEND\">Weekend</a>, ");
            out.println("<a href=\"products?t=1W\">1 Week</a>, ");
            out.println("<a href=\"products?t=1M\">1 Month</a>, ");
            out.println("<a href=\"products?t=3M\">3 Month</a>, ");
            out.println("<a href=\"products?t=YTD\">Year To Date</a>, ");
            out.println("<a href=\"products?t=1Y\">1 Year</a>, ");
            out.println("<a href=\"products?t=3Y\">3 Year</a>");
            out.println("<table>");
            System.out.println("HTML print 1:" + System.nanoTime());
            List sales = productDAO.getProducts(interval);
            System.out.println("Fetched sqles list:" + System.nanoTime());
            for (Iterator iterator = sales.iterator(); iterator.hasNext();) {
                out.println("<tr>");
                LinkedCaseInsensitiveMap next = (LinkedCaseInsensitiveMap) iterator.next();
                out.println("<td>" + next.get("REFERENCE") + "</td>");
                out.println("<td>" + next.get("NAME") + "</td>");
                out.println("<td>" + next.get("UNITS") + "</td>");
                out.println("</tr>");
            }
            System.out.println("Print data:" + System.nanoTime());
            out.println("</table>");
            out.println("</body>");
            out.println("</html>");
        }
    }

    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /**
     * Handles the HTTP <code>GET</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Handles the HTTP <code>POST</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Returns a short description of the servlet.
     *
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>

}

productAnalyticsDAO.java(数据访问对象)

public class productAnalyticsDAO extends JdbcDaoSupport {
    public List<String[]> getProducts(String interval){
        System.out.println("Entered getProducts:" + System.nanoTime());
        String sql = "SELECT PRODUCTS.REFERENCE, "
                + "PRODUCTS.NAME, "
                + "PRODUCTS.CATEGORY, "
                + "SUM(TICKETLINES.UNITS) AS UNITS, "
                + "SUM(TICKETLINES.UNITS * TICKETLINES.PRICE) AS TOTAL "
                + "FROM RECEIPTS, "
                + "TICKETS, "
                + "TICKETLINES, "
                + "PRODUCTS "
                + "WHERE RECEIPTS.ID = TICKETS.ID "
                + "AND TICKETS.ID = TICKETLINES.TICKET "
                + "AND TICKETLINES.PRODUCT = PRODUCTS.ID ";
                if(interval.equals("today")){
                    sql += "AND DATE(RECEIPTS.DATENEW)= CURDATE() ";
                }
                if(interval.equals("1D")){
                    sql += "AND DATE_SUB(CURDATE(),INTERVAL 1 DAY) <= DATE(RECEIPTS.DATENEW) ";
                }
                if(interval.equals("1W")){
                    sql += "AND DATE_SUB(CURDATE(),INTERVAL 1 WEEK) <= DATE(RECEIPTS.DATENEW) ";
                }
                if(interval.equals("WEEKEND")){
                    sql += "AND DATE_SUB(CURDATE(),INTERVAL 1 WEEK) <= DATE(RECEIPTS.DATENEW) ";
                    sql += "AND DAYOFWEEK(DATE(RECEIPTS.DATENEW))=1 OR DAYOFWEEK(DATE(RECEIPTS.DATENEW))=7 ";
                }
                if(interval.equals("1M")){
                    sql += "AND DATE_SUB(CURDATE(),INTERVAL 1 MONTH) <= DATE(RECEIPTS.DATENEW) ";
                }
                if(interval.equals("3M")){
                    sql += "AND DATE_SUB(CURDATE(),INTERVAL 3 MONTH) <= DATE(RECEIPTS.DATENEW) ";
                }
                if(interval.equals("YTD")){
                    sql += "AND YEAR(RECEIPTS.DATENEW)= YEAR(CURDATE()) <= DATE(RECEIPTS.DATENEW) ";
                }
                if(interval.equals("1Y")){
                    sql += "AND  DATE_SUB(CURDATE(),INTERVAL 1 YEAR) <= DATE(RECEIPTS.DATENEW) ";
                }
                if(interval.equals("3Y")){
                    sql += "AND  DATE_SUB(CURDATE(),INTERVAL 3 YEAR) <= DATE(RECEIPTS.DATENEW) ";
                }
                sql += "AND NOT PRODUCTS.CATEGORY = \"9286649c-00e1-428a-bd45-b47a1e0154b4\" " // filter out ophaal uren
                + "GROUP BY PRODUCTS.CATEGORY, PRODUCTS.NAME "
                + "ORDER BY PRODUCTS.NAME";

        System.out.println("Builded SQL string:" + System.nanoTime());
        List myBook = getJdbcTemplate().queryForList(sql);
        System.out.println("Fetched data:" + System.nanoTime());
        return myBook;
    }

我使用System.nanoTime()来计算不同点之间的弧线:

  • 从xml创建的上下文:4943507136673
  • getbean for the DAO:4943507261046 // - &gt; arc:0.124373毫秒
  • 从请求中获取时间参数:4943507687437 // - &gt; arc:0.426391毫秒
  • HTML print 1:4943507916077 // - &gt; arc:0.228640毫秒
  • 已输入getProducts:4943507993097 // - &gt; arc:0.077020毫秒
  • 构建的SQL字符串:4943508103467 // - &gt; arc:0.110370毫秒
  • 摘要数据:4980514095087 // - &gt; arc:37005.991620毫秒
  • Fetched sqles列表:4980514152604 // - &gt; arc:0.057517毫秒
  • 打印数据:4980515844896 // - &gt; arc:1.692292毫秒

那么,为什么getJdbcTemplate().queryForList(sql)需要这么慢...... 数据库在localhost上,通过phpMyAdmin执行sql语句的速度要快得多...... Showing rows 0 - 31 (32 total, Query took 0.1411 seconds.)

编辑:执行的最终SQL命令是:SELECT PRODUCTS.REFERENCE, PRODUCTS.NAME, PRODUCTS.CATEGORY, SUM(TICKETLINES.UNITS) AS UNITS, SUM(TICKETLINES.UNITS * TICKETLINES.PRICE) AS TOTAL FROM RECEIPTS, TICKETS, TICKETLINES, PRODUCTS WHERE RECEIPTS.ID = TICKETS.ID AND TICKETS.ID = TICKETLINES.TICKET AND TICKETLINES.PRODUCT = PRODUCTS.ID AND DATE(RECEIPTS.DATENEW)= CURDATE() AND NOT PRODUCTS.CATEGORY = "9286649c-00e1-428a-bd45-b47a1e0154b4" GROUP BY PRODUCTS.CATEGORY, PRODUCTS.NAME ORDER BY PRODUCTS.NAME

谢谢你, 罗宾

1 个答案:

答案 0 :(得分:0)

  1. 一种可能性是查询形成可能会减慢结果 查询应该是这种格式

    来自收据 LEFT OUTER JOIN TICKETS ON RECEIPTS.ID = TICKETS.ID LEFT OUTER JOIN TICKETLINES ON TICKETS.ID = TICKETLINES.TICKET 左外联产品 ON TICKETLINES.PRODUCT = PRODUCTS.ID

  2. 您还可以尝试indexing列,这样可以让它更快地运行,但在评估后使用它