один и тот же запрос, два разных способа, совершенно разная производительность - PullRequest
1 голос
/ 14 февраля 2012

У меня есть таблица Postgres с более чем 8 миллионами строк.Учитывая следующие два способа выполнения одного и того же запроса с помощью DBD::Pg, я получаю совершенно разные результаты.

$q .= '%';

## query 1
my $sql = qq{
    SELECT a, b, c
    FROM t 
    WHERE Lower( a ) LIKE '$q'
};
my $sth1 = $dbh->prepare($sql);
$sth1->execute();

## query 2
my $sth2 = $dbh->prepare(qq{
    SELECT a, b, c
    FROM t  
    WHERE Lower( a ) LIKE ?
});
$sth2->execute($q);

запрос 2 как минимум на порядок медленнее, чем запрос 1 ...не использует индексы, в то время как запрос 1 использует индекс.

Хотелось бы услышать почему.

Ответы [ 5 ]

5 голосов
/ 14 февраля 2012

При использовании выражений LIKE индексы b-дерева могут использоваться только в том случае, если шаблон поиска привязан слева, т. Е. заканчивается %. Подробнее в руководстве .
Спасибо @evil otto за ссылку.Эта ссылка на текущую версию.

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

Ваш второй запрос не предоставляет никакой информации о шаблоне во время подготовкипоэтому планировщик запросов не может использовать индексы.

1 голос
/ 14 февраля 2012

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

0 голосов
/ 14 февраля 2012

Ааа, понятно - я выпаду после этого комментария, так как не знаю Perl.Но я бы поверил, что редактор правильно выделил $ q как константу.Я предполагаю, что вам нужно объединить значение в строку, а не просто напрямую ссылаться на переменную.Итак, я предполагаю, что если + используется для конкатенации строк в Perl, то используйте что-то вроде:

my $ sql = qq {SELECT a, b, c ОТ ГДЕ Lower (a) LIKE '} +$ q + qq {'};

(Примечание: если язык тесно не интегрирован с базой данных, такой как Oracle / PLSQL, перед отправкой в ​​базу данных обычно требуется создать полностью допустимую строку SQLожидая, что компилятор «интерполирует» / «подставит» значение переменной.)

Я бы снова предложил получить COUNT () операторов, чтобы убедиться, что вы сравниваете яблоко с яблоками.

0 голосов
/ 14 февраля 2012

Запускаете ли вы оба теста из одного и того же файла, используя один и тот же объект $ dbh? Я думаю, что причиной увеличения скорости во втором случае является то, что вы используете подготовленное выражение, которое уже проанализировано (но, возможно, я ошибаюсь:)).

0 голосов
/ 14 февраля 2012

Я вообще не знаю Postgres, но я думаю, что в строке 7 (ГДЕ ниже (a) КАК '$ q' ), $ q на самом деле является константой. Похоже, ваш редактор тоже так думает, поскольку он выделен красным. Вы, вероятно, все еще должны использовать? для переменной.

Чтобы проверить, сделайте СЧЕТ (*) и убедитесь, что они совпадают - я могу быть далеко за пределами базы.

...