Почему SQL select занимает больше процессорного времени в Java? - PullRequest
2 голосов
/ 06 августа 2009

У меня есть веб-приложение Java, которое выбирает один столбец из таблицы (с 6 миллионами строк), и это занимает много процессорного времени Этот выбор (SELECT id FROM mytable WHERE filename = 'unique_filename') занимает значительно меньше времени при выполнении в браузере запросов.

Что может вызвать это?
С чего мне начать искать узкие места?

База данных MSSQL 2005 Standard
Контейнер Java - Tomcat 5.5 (с sqljdbc 1.2)

Подробнее:
1.Ява код

 ResultSet rs = null;    
 PreparedStatement stmt = null;
 Connection conn = null;
 Integer myId=null;
 String myVeryUniqueFileName = strFromSomeWhere;
 try
 {
    conn = Database.getConnection();
    stmt = conn.prepareStatement("SELECT id FROM mytable WHERE filename = ?");
    stmt.setString(1, myVeryUniqueFileName);

    rs = stmt.executeQuery();
    if (rs.next())
    {
       myId= new Integer(rs.getInt(1));
    }              }
    if (rs.next())
    {
       throw new DBException("Duplicate myId: " + myId);
    }
    return myId;
 } catch (Exception e) {
    // handle this
 }

Объект базы данных использует DriverManager для получения объекта подключения.

2. В таблице SQL содержится около 30 столбцов.

 CREATE TABLE [dbo].[calls](    
    [id] [int] NOT NULL,     
    ...    
    [filename] [varchar](50) NOT NULL,
    ...     
 CONSTRAINT [PK_xxxxxxxxxxxx] PRIMARY KEY CLUSTERED     
 (    
    [id] ASC    
 )WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY],     
 CONSTRAINT [UQ_xxxxxxxxxxxx] UNIQUE NONCLUSTERED       
 (      
    [filename] ASC     
 )WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]     
 ) ON [PRIMARY]    

Столбец имени файла уникален, поэтому набор результатов всегда равен 1 или нулю.

Ответы [ 5 ]

2 голосов
/ 15 августа 2009

С помощью более умного разработчика я смог решить эту проблему. Оказывается, я неправильно использовал PreparedStatement ( aricle ).

На основании этого я изменил код Java на:

ResultSet rs = null;    
Statement stmt = null;
Connection conn = null;
Integer myId=null;
String myVeryUniqueFileName = strFromSomeWhere;
try
{
  conn = Database.getConnection();
  stmt = conn.createStatement()
  //
  rs = stmt.executeQuery("SELECT id FROM mytable WHERE filename = '"
                         + myVeryUniqueFileName + "'");
  if (rs.next())
  {
    myId= new Integer(rs.getInt(1));
  }              
  if (rs.next())
  {
    throw new DBException("Duplicate myId: " + myId);
  }
  return myId;
} catch (Exception e) {
  // handle this
}

После этого нагрузка на дабабазу снизилась в среднем с 70% до 13%

1 голос
/ 07 августа 2009

Я не могу говорить конкретно с MSSQL 2005, но может быть разница в плане выполнения между подготовленным оператором, в котором вы используете переменные связывания, и эквивалентными операторами, в которые встроены значения.

Чтобы проверить эту теорию, удалите параметр bind и вместо этого объедините SQL-запрос в Java с фактическим именем файла (в кавычках). Таким образом, вы сравниваете яблоки с яблоками.

Кроме того, это было бы полезно с указанием разницы в времени процессора, которое вы испытываете. Это несколько порядков или меньше 100%.

1 голос
/ 06 августа 2009

Можете ли вы опубликовать свой код Java, где вы выполняете этот запрос и получаете результаты?

Возможные факторы, заставляющие код Java казаться значительно дольше:

  1. Ваш запрос возвращает большое количество записей, и вы пытаетесь получить их все в Java, тогда как браузер запросов будет показывать только первые 100 (независимо от того, какое это число может быть) и загружать другие по запросу.
  2. Вы сравниваете разное время, например, "запрос занял X мс", отображаемый браузером запросов, со временем, которое требуется Java для получения соединения до его закрытия.
  3. Ваши объекты (содержащие результаты) могут быть дорогими в создании, или они могут выполнять некоторую обработку за кулисами, когда они заполнены.
0 голосов
/ 06 августа 2009

Вы используете утверждение, а не подготовленное заявление. Оператор не будет предварительно скомпилирован и кэширован, поэтому оптимизатор запросов должен выполнять эту работу каждый раз. Если вы используете подготовленный оператор, он попытается найти лучший способ выполнить ваш запрос и сохранить его. В следующий раз, когда вы воспользуетесь им, он не будет пытаться найти хороший способ получить ваши результаты, это будет только план выполнения, который у него уже есть.

0 голосов
/ 06 августа 2009

Симптомы, которые вы описываете, чаще всего вызваны неверно кэшированным планом запроса.

Перестройте свои индексы или обновите статистику.

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