Почему намного быстрее передать массив как литерал, а не параметр? - PullRequest
3 голосов
/ 02 мая 2020

У меня есть запрос, подобный следующему:

SELECT
   table1.field1,
   table1.field2,
   table3.field1,
   table3.field2,
   table3.field3,
   table3.field4

FROM table1

INNER JOIN table2
ON table1.field1 = table2.field1

INNER JOIN table3
ON table2.field2 = table3.field5

WHERE table1.field1 = ANY(@pArray);

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

Мне интересно, почему приведенный выше параметр заставляет этот запрос занимать 10+ секунд, тогда как если я передаю массив вручную как литерал массива (с использованием конкатенации строк), тогда это занимает около 40-50 миллисекунд.

Мой массив содержит 195 8-значных числительных c строковых элементов.

Мое единственное предположение, что это имеет какое-то отношение к очистке значений параметров, но выполнение запроса в сотни раз дольше кажется чрезмерным. Что я сделал, так это добавил свою собственную проверку, чтобы убедиться, что все строки имеют 100% -ное число c, что, как мне кажется, должно предотвратить SQL атаки с использованием инъекций.

Мой код Npg Sql выглядит как это:

void MyQuery(
   string[] pArray
) {
   var sql = @"
      // as above
   ";

   using var connection = new NpgsqlConnection(mConnectionString);
   connection.Open();

   using var command = new NpgsqlCommand(sql, connection);
   command.Parameters.AddWithValue("pArray", pArray);

   // takes ~12 seconds with parameter, or ~50ms with array literal
   using var reader = command.ExecuteReader();

При удалении параметра, предложение WHERE в конечном итоге выглядит примерно так, после констатации:

WHERE table1.field1 = ANY('{12345678,12345679,12345680,12345681}');

Является ли медлительность только из-за очистки, или ошибка в Npg Sql или что-то еще?

1 Ответ

1 голос
/ 03 мая 2020

Проблема, указанная в комментариях, заключалась в добавлении параметра без указания типа. Изменение строки параметра на следующее решило проблему:

command.Parameters.AddWithValue("pArray", NpgsqlDbType.Array | NpgsqlDbType.Char, pArray);

Обратите внимание, что для указания типа массива вы ИЛИ значение Array с другим значением, в данном случае Char. Фактический тип PostgreSQL в базе данных похож на character varying(15).

...