简体   繁体   中英

JdbcDaoSupport queryForList slow

I'm trying to make a simple servlet to display some data from my database using spring framework JdbcDaoSupport. Executing one single "SELECT"-sql command takes up about 25-35 seconds. And Im pretty new to spring and i don't get why this takes so long...

Here is my code: 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 (the actual 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 (The Data access object)

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;
    }

I'm using System.nanoTime() to calculate the arcs between different points:

  • context created from xml:4943507136673
  • getbean for the DAO:4943507261046 //-> arc : 0.124373 milliseconds
  • fetch time parameter from request:4943507687437 //-> arc : 0.426391 milliseconds
  • HTML print 1:4943507916077 //-> arc : 0.228640 milliseconds
  • Entered getProducts:4943507993097 //-> arc : 0.077020 milliseconds
  • Builded SQL string:4943508103467 //-> arc : 0.110370 milliseconds
  • Fetched data:4980514095087 //-> arc : 37005.991620 milliseconds
  • Fetched sqles list:4980514152604 //-> arc : 0.057517 milliseconds
  • Print data:4980515844896 //-> arc : 1.692292 milliseconds

So, why does the getJdbcTemplate().queryForList(sql) takes so slow... The database is on localhost and executing the sql statement via phpMyAdmin goes much much quicker... Showing rows 0 - 31 (32 total, Query took 0.1411 seconds.)

Edit: Final SQL command executed is: 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

Thank you, Robin

  1. One possibility is the query formation which could be slowing down the result The query should be if this format

    FROM RECEIPTS LEFT OUTER JOIN TICKETS ON RECEIPTS.ID = TICKETS.ID LEFT OUTER JOIN TICKETLINES ON TICKETS.ID = TICKETLINES.TICKET LEFT OUTER JOIN PRODUCTS ON TICKETLINES.PRODUCT = PRODUCTS.ID

  2. You can also try indexing the columns which will make it run faster but use it after through evaluation

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM