2009-09-08 1 views
3

Ситуация: C#, sql 2000Почему параметры медленнее, чем литеральные значения в предложении where?

У меня есть таблица, давайте назовем ее «mytable» с 30 миллионами строк. Первичный ключ состоит из полей А и В:

A char(16) 
B smallint(2) 

Когда я делаю поиск, как это, она работает очень медленно (например, это делает полный просмотр таблицы)

string a="a"; 
int b=1; 
string sql = "select * from table(nolock) where [email protected] and [email protected]"; 
using (SqlCommand cmd = new SqlCommand(sql, conn)) 
{ 
    cmd.Parameters.AddWithValue("@a", a); 
    cmd.Parameters.AddWithValue("@b", b); 
    using (SqlDataReader rdr = cmd.ExecuteReader()) {...} 
} 

Изменить его однако, он работает очень быстро (например, он попадает в индекс):

string where = 
    String.Format("a='{0}' and b={1}", a, b); 

string sql = "select * from table(nolock) where " + where; 
using (SqlCommand cmd = new SqlCommand(sql, conn)) 
{ 
    using (SqlDataReader rdr = cmd.ExecuteReader()) {...} 
} 

Что происходит? Кажется странным для меня.

+0

Попробуйте перезагрузить сервер базы данных и отмените порядок своих тестов.Цель всего этого - исключить кеширование на стороне SQL Server. –

+0

К сожалению, это не вариант для производственного сервера. – Chris

+0

Это может помочь - но может и не быть: http://stackoverflow.com/questions/1211287/getting-a-query-to-index-seek-rather-than-scan – PaulB

ответ

8

Совместимы ли типы данных с параметрами и столбцами? Они не выглядят так datatype precedence прилагается

Столбец маленький, но вы отправляете int. Столбец будет преобразован в int, поскольку он имеет более высокий приоритет. Поэтому он не будет использовать индекс.

+0

Использование несоответствующих типов является распространенной ошибкой, которую я засвидетельствовал и попал в себя. и да, если это поле, которое неявно преобразуется (а не параметр), вы можете получить ну и правду #### ed. понимание приоритета типа и того, как работают индексы (и не работают), помогут понять здесь. – MatBailie

3

Не имеет значения, если вы объявляете переменную b равной short вместо int? Не имеет значения, если вы явно указываете типы параметров? Не имеет значения, если вместо запятой использовать «где a = @ a и b = @ b»?

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

+0

Извините, запятая была просто меня очень сильно расшифровывала мой код. Починю. Что касается коротких, стоит попробовать. – Chris

+0

Настройка параметров типа стоит попробовать. –

+0

На самом деле это будет иметь огромное значение ... – gbn

0

Вы можете указать SQL Server, какой индекс использовать для запроса. Используйте опцию WITH (INDEX = INDEX_ID), где INDEX_ID - это идентификатор индекса.

Получить идентификатор индекса с:

SELECT i.indid, i.name FROM sysindexes i 
INNER JOIN sysobjects o ON o.ID = i.id 
WHERE o.Name = 'table' 

Так попытайтесь тогда:

SELECT * FROM table(NOLOCK) WITH (INDEX = 1) WHERE [email protected] and [email protected] 
+0

Действительно ли сервер sql настолько толстый, что мне нужно намекнуть на индексы? – Chris

+0

@ Крис: нет: это потому, что у вас есть несоответствие типа данных. Указатель индекса не поможет. – gbn

+0

Мне никогда не приходилось, но вариант существует – Scoregraphic

0

Как @gbn сказал, устанавливая тип данных должны сделать его легким для вас.

string where = 
    String.Format("a='{0}' and b={1}", a, b); 

В приведенном выше примере вы сообщаете SQL для обработки параметра a как char.
Принимая во внимание, что в другом примере это будет рассматриваться как варчар.

Используйте SQL-профайлер, чтобы узнать, что такое SQL, который запускается в обоих случаях. Это должно очистить его для вас.

0

В первом случае вы добавляете классы SqlParameter в команду. Когда команда выполняется, она скорее всего генерирует операторы DECLARE с неправильным типом данных. (Вы можете проверить это с помощью трассировки SQL.) Если это так, оптимизатор не может выбрать правильный индекс и возвращается к сканированию таблицы.

Если вы используете хранимую процедуру вместо этого, вы будете принудительно вводить параметры в типы данных, которые вы объявляете. Однако вы все равно можете сделать это из кода, если вы укажете SqlDbType для параметров.