Я использую SQLSRV 4.3 PDO с PHP 7.1. Я уже проверял это на SQLSRV 3.2 с PHP 5.6 тоже. Итак, у меня есть следующий запрос:
$sql = "select [ID], [Year], [Month], sum(Value) as Value,
MIN(FirstDateTime) as FirstDateTime, MAX(SecondDateTime) as
SecondDateTime from [ValuesTable] where [FirstDateTime] >= ? and
[SecondDateTime] <= ? and [Year] in (?) GROUP BY [ID],
[Year], [Month] order by [ID] offset 0 rows fetch next 30 rows only";
И его параметры:
$param1 = '2017-10-01 00:00:00';
$param2 = '2017-10-31 23:59:59';
$param3 = '2017';
Когда я выполняю запрос со следующим кодом:
$result = $db->prepare($sql)
$result->bindParam(1, $param1);
$result->bindParam(2, $param2);
$result->bindParam(3, $param3);
$result->execute();
Требуется вечность, чтобы закончить. Если вместо этого я выполняю следующий небезопасный запрос:
$sql = "select [ID], [Year], [Month], sum(Value) as Value,
MIN(FirstDateTime) as FirstDateTime, MAX(SecondDateTime) as
SecondDateTime from [ValuesTable] where [FirstDateTime] >= '2017-10-01 00:00:00' and
[SecondDateTime] <= '2017-10-31 23:59:59' and [Year] in (2017) GROUP BY [ID],
[Year], [Month] order by [ID] offset 0 rows fetch next 30 rows only";
Это не займет много времени, чтобы завершить.
Я проверил много и исследовал много, и я не мог найти ответ на свою проблему.
Я уже установил атрибуты для PDO, например
$db->setAttribute( \PDO::SQLSRV_ATTR_ENCODING, \PDO::SQLSRV_ENCODING_SYSTEM );
$db->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
Кроме того, я помещаю типы параметров в функцию bindParam()
, как в
$result->bindParam(1, $param1, PDO::PARAM_STR);
$result->bindParam(2, $param2, PDO::PARAM_STR);
$result->bindParam(3, $param3, PDO::PARAM_INT);
Я также изменил тип курсора с помощью следующего кода
$result = $db->prepare($sql, array(
\PDO::ATTR_CURSOR => \PDO::CURSOR_SCROLL,
\PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE => \PDO::SQLSRV_CURSOR_BUFFERED
)
);
Параметризованный запрос все еще выполняется вечно, ничего не изменилось.
Кроме того, выполнили следующие тесты только для того, чтобы предотвратить кэш-память запросов SQL Server или что-то еще:
- Перезапущенный Sql-сервер
- выполнил параметризованный запрос, и для его завершения потребовалось целое время
- Перезапущенный Sql-сервер
- Выполнил небезопасный запрос и быстро его выполнил
Кто-нибудь догадывается, что я делаю не так?
О, я забыл упомянуть одну вещь: таблица "ValuesTable" - это секционированное представление, в котором есть таблица для каждого года. Как ValuesTable2016, ValuesTable2017. Каждая таблица имеет проверочное ограничение, поэтому оптимизатор запросов будет знать, какие таблицы включить в запрос.
Представление создается с помощью следующего сценария:
CREATE View [dbo].[ValuesTable] as
SELECT * FROM ValuesTable2016 UNION ALL
SELECT * FROM ValuesTable2017 UNION ALL
SELECT * FROM ValuesTable2018
Если я выполню параметризованный запрос, используя TABLE, а не секционированный VIEW, как
$sql = "select [ID], [Year], [Month], sum(Value) as Value,
MIN(FirstDateTime) as FirstDateTime, MAX(SecondDateTime) as
SecondDateTime from [ValuesTable2017] where [FirstDateTime] >= ? and
[SecondDateTime] <= ? and [Year] in (?) GROUP BY [ID],
[Year], [Month] order by [ID] offset 0 rows fetch next 30 rows only";
Запрос выполняется быстро, как в небезопасном. Но, очевидно, мне нужно использовать разделенное представление, так что это не вариант.
Небезопасный запрос всегда выполняется быстро, используя секционированное представление или таблицу.
Так что нет смысла предлагать мне изменить его структуру. Дело в том, что непараметризованный запрос выполняется быстро, а параметризованный - навсегда.
Еще одна вещь: я уже тестировал его без pdo, используя sqlsrv_prepare с параметрами связывания и выполняя его с помощью sqlsrv_execute. Он также работает очень медленно.