Как я могу заставить MS-Access выбрать другой / правильный план выполнения для моего запроса - PullRequest
5 голосов
/ 27 января 2012

У меня проблема с относительно простым запросом, и план выполнения Access выбирает его.

Запрос имеет такую ​​форму

SELECT somethings
FROM A INNER JOIN (B INNER JOIN (C INNER JOIN D ON ...) ON ...) ON ...
WHERE A.primaryKey= 1 AND D.d = 2;

C и D имеют относительно небольшое количество строк.A и B имеют несколько тысяч строк.

Запрос, который возвращает 2 строки (не уверен, что это уместно), действительно медленный.Работает за 17 секунд.Если я удаляю часть AND D.d = 2 предложения where, запрос теперь возвращает 4 строки и выполняется мгновенно.

Итак, насколько я понимаю, механизм JET может выполнить запрос без фильтра для Dd мгновенно, а затем выполнитьуказанный фильтр мгновенно (только 4 строки для фильтрации).Поэтому выполнение запроса с фильтром D.d = 2 не должно быть слишком долгим.

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

Поскольку я не смог выполнить запрос так, как мне хотелось, я использовал JETSHOWPLAN так,Доступ выведет его план выполнения.Вот что я нашел:

Для быстрого запроса (без D.d = 2) первым шагом плана запроса является применение фильтра A.primaryKey = 1 к таблице A.В результате получается набор данных из 1 строки из более чем 30000. Затем, кажется, что объединения выполняются из A в D с использованием индекса с набором данных, который никогда не превышает 4 строки.

Медленный запросисполняться в порядке реверса.Сначала соединяются D и C, затем проверяется D.d = 2.После этого соединения от C до A выполняются.Делая это таким образом, данные, которые необходимо объединить из D в C, из C в B и из B в A, намного больше.Когда все JOIN будут выполнены и перед выполнением A.primaryKey=1 в наборе данных будет 120K строк.

Можно ли как-то принудительно настроить правильный план запроса в Access?

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

Заранее спасибо,

mp

Ответы [ 2 ]

2 голосов
/ 28 января 2012

Я наконец заставил его работать, перемешивая, пока планировщик запросов не согласился со мной.Я выделил «A.primaryKey = 1» в подзапросе, чтобы убедиться, что он выполняется до присоединения A к B. Это примерно так:

SELECT ... 
FROM (SELECT ... FROM A WHERE a.primaryKey=1) AS qryA
   INNER JOIN B ...
WHERE D.d = 2;
2 голосов
/ 27 января 2012

Делать это в коде VBA? Идея заключалась бы в том, чтобы убрать медленную часть и выполнить быстро возвращающийся запрос, а затем добавить медленную часть в sql.

db.execute "select * from qryFast inner join d on qryfast.dkey = d.d where d.d = 2

Нет, код VBA в модуле отличается от подзапроса. @HansUp разъяснил нам, что выполнение кода за один шаг, как я показал выше, не улучшит производительность. Вы должны быть в состоянии быстро получить результаты в памяти, если вы знакомы с написанием кода в модулях, но тогда получение вывода в нужном месте может еще больше замедлить работу.


другими словами, вы должны иметь возможность быстро получить результаты qryFast в набор записей в памяти, а затем применить фильтр к qryFast.dkey = d, а также быстро получить набор записей из 'select * from tableD, где d = 2 ', чтобы найти необходимую информацию из таблицы D, но выгрузка всей этой информации из памяти в место, где ваш интерфейс может получить к ней доступ, может занять больше, чем 17 секунд, которые они ждут сейчас.


На самом деле, это может привести к ударам в штаны, если вы измените qryFast, чтобы включить условие, где dkey = 2 (или что-то еще, что pk находится на tableD)


другая идея: объединить 3 запроса: qryFast, qryD и qryFastWithD. Я просто выбрасываю идеи, здесь.


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

...