Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > Оптимизация подсчета суммы


Автор: scyther 2.6.2008, 14:37
Есть метод getMiddleTimeView который возвращает среднее время просмотра. Список list формируется по SQL запросу, который возвращает около 1'000'000 элементов.
Вот задача: как оптимизировать этот метод? Скорость выдачи результата очень медленная :( порядка 30..50 секунд
sumSessions - тут можна получить сумму из SQL, а как быть с allTime?

Код
public String getMiddleTimeView(Long partnerId) {
        List<UserTimeOnPartner> list = SessionsDAO.getDefaultDao().getUserTimeOnPartner(partnerId);
        Double sumSessions = 0.0;
        Double allTime = 0.0;
        Double result = null;
        String res = null;
        
        for (int i = 0; i < list.size(); i++) {
            Double temp = list.get(i).getTimeIn();
            
            if(temp.equals(0.0))
                temp = 0.1;
            
            sumSessions = list.get(i).getSessions() + sumSessions;
            allTime = (temp * list.get(i).getSessions()) + allTime; 
        }
        
        result = allTime/sumSessions;
        res = new java.text.DecimalFormat("0.00").format(result);
        
        return res;
    }

Автор: LSD 2.6.2008, 14:52
Поподробней насчет данных, как что хранится.

Автор: w38 2.6.2008, 14:52
что сразу бросилось в глаза:
1) проход по списку сделать итератором, вместо for (int i = 0; i < list.size(); i++)
2) избавиться от неявных оберток Double -> double
про подсчет allTime на стороне сервера, что мешает использовать условные констуркции в SQL-выражениях, процедруах или представлениях ?

Автор: scyther 2.6.2008, 15:17
LSD: вот тип ArrayList'а, остальное впринципе видно в первом посте 
Код
public class UserTimeOnPartner {
    private Integer userId = null;
    private Long partnerId = null;
    private Double timeIn = null;
    private Double sessions = null;

w38: "использовать условные констуркции в SQL-выражениях" - а можна, пожалуста, подробней об етом (или ссылки какие)

Автор: Kangaroo 2.6.2008, 15:17
Цитата(scyther @  2.6.2008,  14:37 Найти цитируемый пост)
list.get(i)


Цитата(scyther @  2.6.2008,  14:37 Найти цитируемый пост)
list.get(i)


Цитата(scyther @  2.6.2008,  14:37 Найти цитируемый пост)
list.get(i)

зачем три раза рыться по массиву? Раз достань и используй.


Может можно СКЛюм сделать sum(TimeIn*Sessions), я не уверен.

Автор: scyther 2.6.2008, 15:39
Kangaroo: "sum(TimeIn*Sessions), я не уверен" можно.
Немного переписал метод 
Код
public String getMiddleTimeView(Long partnerId) {
        List<UserTimeOnPartner> list = SessionsDAO.getDefaultDao().getUserTimeOnPartner(partnerId);
        double sumSessions = 0.0;
        double allTime = 0.0;
        double result = 0.0;
        String res = null;
        for(UserTimeOnPartner p : list) {
            double t = p.getTimeIn();
            double s = p.getSessions();
            if(t == 0.0)
                t = 0.1;
            sumSessions = s + sumSessions;
            allTime = (t * s) + allTime;
        }
        result = allTime/sumSessions;
        res = new java.text.DecimalFormat("0.00").format(result);
        return res;
    }

Новый код - новые ошибки
Код
java.lang.OutOfMemoryError: Java heap space
    at com.mysql.jdbc.MysqlIO.nextRow(MysqlIO.java:1015)
    at com.mysql.jdbc.MysqlIO.getResultSet(MysqlIO.java:305)
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1326)
    at com.mysql.jdbc.Connection.execSQL(Connection.java:2281)
    at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:1634)
    at biz.smartymedia.usrating.dao.impl.SessionsDAOImpl.getUserTimeOnPartner(SessionsDAOImpl.java:148)
    at biz.smartymedia.usrating.service.impl.SessionsServiceImpl.getMiddleTimeView(SessionsServiceImpl.java:46)
    at test.biz.smartymedia.usrating.service.TestSessionsService.testAllSessionsService(TestSessionsService.java:20)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at junit.framework.TestCase.runTest(TestCase.java:164)
    at junit.framework.TestCase.runBare(TestCase.java:130)
    at junit.framework.TestResult$1.protect(TestResult.java:106)
    at junit.framework.TestResult.runProtected(TestResult.java:124)
    at junit.framework.TestResult.run(TestResult.java:109)
    at junit.framework.TestCase.run(TestCase.java:120)
    at junit.framework.TestSuite.runTest(TestSuite.java:230)
    at junit.framework.TestSuite.run(TestSuite.java:225)
    at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)


Автор: Platon 2.6.2008, 15:54
В миллион записей, ты конечно прикалываешься выгружать в память! Раз ты игнорируешь получать данные с помощью SQL-скрипта, тогда прими к сведению:
Лучше делать страничную выгрузку данных. Что имею ввиду:
Код

List items;
from = 0;
limit = 1000;
do {
    items = dao.getItems(from, limit);
    // частично получаешь сумму
    from += limit;
} while (items.size() != 0);

// здесь у тебя есть сумма, теперь просто делишь.

Автор: scyther 2.6.2008, 17:49
Platon: спасиба, вопрос решен smile 

Автор: LSD 2.6.2008, 18:49
Цитата(scyther @  2.6.2008,  16:17 Найти цитируемый пост)
вот тип ArrayList'а, остальное впринципе видно в первом посте

Я имел в виду, пояснить что там к чему. По коду не очень понятен смысл timeIn и sessions.

А вообще самое быстрое и производительное это посчитать сумму в БД.

Автор: scyther 3.6.2008, 13:07
LSD: так и сделал, все в sql считал,  теперь работает за 0.5 секунды

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)