Оптимизируйте скорость выполнения запроса «выбор» в большом цикле - PullRequest
7 голосов
/ 05 июля 2011

Я выполняю простой запрос «выбор» в цикле Java, как показано ниже.Размер списка может увеличиться до 10000+.Как я могу улучшить скорость запроса?Любой пример или совет приветствуется.Благодарю.

Обратите внимание, что мне нужно получить все данные в каждом столбце этой таблицы, поэтому используется звездочка (*).

List<String> valueList = ....
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;

try {
    DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
    conn = DriverManager.getConnection(dbURL, dbUsername, dbPassword);
    for (int m = 0; m < valueList.size() ; m++) {    
         String sql = "SELECT * FROM WORKSHEET WHERE " + sheetId + " = '" +    
                      valueList.get(m) + "'";
         ps = conn.prepareStatement(sql);
         rs = ps.executeQuery();
         // retreive data....           
    }
}

Редактировать: В конце естьнесколько способов ускорить этот запрос.Я использую второй способ, поскольку он предотвращает ошибку ORA-04031 в будущем.

  1. Используйте параметризованный запрос SELECT с предложением IN.
  2. Создание вложенной таблицы и приведение массива / списка элементов, поступающих из JDBC в созданную вложенную таблицу.
  3. Создайте временную таблицу и вставьте список элементов.Затем выполните JOIN к основной таблице (1 запрос) и получите результаты.

Ответы [ 8 ]

6 голосов
/ 06 июля 2011

Есть две вещи, которые следует учитывать при попытке ускорить это:

  1. Выполнить этот запрос только один раз для всех листов
  2. Убедитесь, что вы выполняете один и тот же запрос каждый раз,не жестко кодируя значения в. Поскольку эти значения могут изменяться, каждый запрос будет выглядеть как предыдущий, но только с несколькими различными значениями.Это не позволит Oracle повторно использовать предыдущий запрос и приведет к невозможности совместного использования SQL в общем пуле.Это заполнит общий пул.Делайте это достаточно долго, и вы получите сообщения об ошибках ORA-04031.

Способ заключается в использовании типов SQL.Вот пример в PL / SQL.Вы можете использовать тот же принцип в Java.

Сначала создайте таблицу с десятью тысячами ID листа:

SQL> create table worksheet (sheetid)
  2  as
  3   select level
  4     from dual
  5  connect by level <= 10000
  6  /

Table created.

Создайте тип SQL:

SQL> create type mynumbers is table of number;
  2  /

Type created.

В вашем кодезаполните экземпляр типа SQL значениями в вашем "valuelist" и используйте оператор TABLE для преобразования типа в значения таблицы:

SQL> declare
  2    valuelist mynumbers := mynumbers(23,124,987,6123,8923,1,7139);
  3  begin
  4    for r in
  5    ( select ws.sheetid
  6        from worksheet ws
  7           , table(valuelist) vl
  8       where ws.sheetid = vl.column_value
  9    )
 10    loop
 11      dbms_output.put_line(r.sheetid);
 12    end loop;
 13  end;
 14  /
1
23
124
987
6123
7139
8923

PL/SQL procedure successfully completed.

Теперь у вас есть только один SQL в вашем общем пуле и простоодно выполнение этого запроса вместо тысяч.

4 голосов
/ 05 июля 2011

Время тратится в основном на подготовку и выполнение запросов.

Если вместо этого вы запустите один запрос, который вернет все ваши результаты, это значительно ускорит процесс.

, то есть:

String where = "(1=0) "
// first build the where string
for (int m = 0; m < valueList.size() ; m++ ) {
  where = where + " OR (" + sheetId + " = '" + valueList.get(m) + "'";
  }
// then run a single query
sql = "SELECT * FROM WORKSHEET WHERE " + where;
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
// retrieve and handle data. ....
3 голосов
/ 05 июля 2011

Вы должны подготовить sql-запрос со значением IN, а затем выполнить запрос только один раз ...

2 голосов
/ 05 июля 2011

Вот еще несколько идей.

  1. Создайте временную таблицу и вставьте свои (10k) элементы списка.Затем выполните объединение с основной таблицей (1 запрос) и получите результаты.

  2. Создайте хранимую процедуру для получения списка элементов (через вложенную таблицу) в качестве входного и возвращаемого набора результатов.через выходной параметр.

Я бы выбрал вариант 1. потому что он более прост для меня и, вероятно, быстрее.Но вы должны быть осторожны с параллельными сеансами и т. Д. Не знаете, как вы хотите обрабатывать несколько сеансов (будут ли они обмениваться этими данными, будут ли у них отдельные списки данных?).

Что-то рассмотреть в любом случае.

1 голос
/ 06 июля 2011

Вы можете попробовать что-то с предложением: sheetId IN ('1', '2', '3', '4') И, пожалуйста, убедитесь, что столбец sheetId имеет индексный ключ.

1 голос
/ 05 июля 2011

Oracle может принимать до 1000 параметров в предложении IN. Поэтому, если вы используете подготовленный оператор, вы уменьшите количество итераций в 1000 раз. Просто разбейте список на 1000 элементов.

0 голосов
/ 05 июля 2011

Это незначительная вещь, но если вы собираетесь построить запрос динамически (без использования переменных связывания), вы должны использовать createStatement, а не prepareStatement. Существует небольшая нагрузка с prepareStatement, которая вам не нужна.

0 голосов
/ 05 июля 2011

Я не знаю, будет ли это улучшением, но вы можете попробовать выбрать все записи и проверить с помощью кода Java, соответствует ли sheetId.Это то, что вы должны успеть узнать, что лучше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...