Вопрос скорости
- From
- Pavel Korzan (2:5020/400)
- To
- Vladimir Ilyashenko
- Date
- 2006-02-24T18:19:06Z
- Area
- SU.DBMS.SQL
From: "Pavel Korzan" <a7b5@nvartovsk.wsnet.ru>
С добрым утром.
К А97 идет замечательный хелп на русском. В всяком сл. в ru.msaccess говорят
что он куда лучше того, что в более новых версиях - очень рекомендую.
По поводу INNER JOIN. Сам не большой знаток и оптимизатор запросов в акцессе
опять же присутствует, но попробую
в сл. FROM t1, t2 WHERE t1.Key=t2.field1 строится декартово произведение
таблиц (все возможные комбинации ЗАПИСЕЙ этих двух таблиц), а затем
проверяется условие из секции WHERE => много памяти, с ростом кол-ва таблиц
тормоза быстро растут. В сл. FROM t1 INNER JOIN t2 ON t1.Key=t2.field1 -
объединение таблиц, то в худшем сл. акцес выполняет два цикла - во внешнем
выбирается значение поля записи из одной таблицы, а во внутреннем
просматриваются поле из записей др. таблицы на предмет совпадения условия.
Если t1.Key -первичный ключ или имеет уникальный индекс то, ИМХО, записи из t2
попавшие под условие на след. иттерациях внешнего цикла уже не проверяются =>
какое-никакое ускорение. Если t2.field1 внешний ключ, который ссылается на
t1.Key то все еще быстрее за счет индекса, пусть он и является констрейнтом.
Кроме того обычно в WHERE присутствуют и др. условия которые оптимизатор может
приказать выполнить до начала объединения/построения декартова произведения,
снова ускорение.
По поводу второго твоего счастья, если тебе повезет то в результате вот этого:
SELECT tab1.a FROM tab1 LEFT JOIN tab2 ON tab1.a=tab2.y WHERE tab1.b='+' AND
IsNull(tab2.y);
будут выбраны записи удовлетворяющие указанным тобой условиям - b='+' и tab1.a
нет в tab2.y (если в tab1 есть такие записи есс-но) - пользуйся на здоровье.
Дело в том, что у меня А97, иногда, вместо внешнего объединения, выдает
внутреннее (тот самый INNER JOIN вместо LEFT/RIGHT JOIN - про них ниже)
например, при таблицах расположенных в разных базах .mdb тогда ничего выбранно
не будет, но это работает всегда одинаково - т.е. если сработало сразу значит
будет работать по крайней мере пока чего-нибудь не подкрутишь в запросе.
Если не повезло то
SELECT TAB1.Á FROM TAB1 WHERE TAB1.b = '+' AND TAB1.Á <>
ALL(SELECT TAB2.y FROM TAB2)
я бы записал как
SELECT TAB1.Á FROM TAB1 WHERE TAB1.b = '+' AND TAB1.Á NOT
IN(SELECT TAB2.y FROM TAB2)
SELECT TAB1.Á FROM TAB1 WHERE TAB1.b = '+' AND NOT EXISTS
(SELECT TAB2.y FROM TAB2 WHERE TAB2.y = TAB1.a)
^^^^^^^^^^^^^^^^^^^^^ это здесь зачем? Тем более что вложенные запросы в
акцессе не оптимизируются.
Пара вопросов-рекомендаций:
1. tab2.y может содержать только те значения которые УЖЕ есть в tab1.a? Если
да - сделай внешний ключ (а может он уже есть? загляни в схему данных).
2. tab1.b обязательно быть символьными? Логический или целочисленный тип поля
должны дать ускорение в выполнении подобных запросов и смотрятся красивше.
Про внешнее объединение, вот из хелпа по А97:
Операции LEFT JOIN, RIGHT JOIN
Объединяют записи исходных таблиц при использовании в любом предложении FROM.
Синтаксис
FROM таблица_1 [ LEFT | RIGHT ] JOIN таблица_2
ON таблица_1.поле_1 оператор таблица_2.поле_2
Ниже перечислены аргументы операций LEFT JOIN и RIGHT JOIN:
Элемент Описание
таблица_1, таблица_2 Имена таблиц, записи которых подлежат объединению.
поле_1, поле_2 Имена объединяемых полей. Поля должны иметь одинаковый тип
данных и содержать данные одного рода, однако, могут иметь разные имена.
оператор Любой оператор сравнения: "=," "<," ">," "<=," ">=," или "<>".
Дополнительные сведения
Используйте операцию LEFT JOIN для создания левого внешнего объединения, при
котором все записи из первой (левой) таблицы включаются в динамический набор,
даже если во второй (правой) таблице нет соответствующих им записей.
Используйте операцию RIGHT JOIN для создания правого внешнего объединения, при
котором все записи из второй (правой) таблицы включаются в динамический набор,
даже если в первой (левой) таблице нет соответствующих им записей.
Например, операцию LEFT JOIN можно использовать с таблицами "Отделы" (левая) и
"Сотрудники" (правая) для отбора всех отделов, в том числе тех, в которых нет
ни одного сотрудника. Для отбора всех сотрудников, в том числе тех, которые
не приписаны ни к одному отделу, используйте операцию RIGHT JOIN.
Следующая инструкция SQL объединяет таблицы "Типы" и "Товары" по полю
"КодТипа". Результатом является список категорий, в том числе тех, которые не
содержат ни одного товара:
SELECT Категория,
Марка
FROM Типы LEFT JOIN Товары
ON Типы.КодТипа = Товары.КодТипа;
В предыдущем примере поле "КодТипа" используется для объединения таблиц,
однако, не включается в результат выполнения запроса, поскольку не включено в
инструкцию SELECT. Чтобы включить связующее поле (в данном случае поле
Типы.КодТипа) в результат выполнения запроса, включите имя этого поля в
инструкцию SELECT.
Примечания
· Если требуется включить в результат только те записи, которые имеют
одинаковые значения в связующих полях, используйте операцию INNER JOIN.
· Операции LEFT JOIN или RIGHT JOIN могут быть вложены в операцию INNER JOIN,
но операция INNER JOIN не может быть вложена в операцию LEFT JOIN или RIGHT
JOIN. Более подробные сведения по этому вопросу можно найти в описании
операции INNER JOIN.
· Можно связать несколько предложений ON. Более подробные сведения по этому
вопросу можно найти в описании операции INNER JOIN.
· Попытка объединить поля Memo или объекта ActiveX приведет к возникновению
ошибки.
Будь здоров.
--- ifmail v.2.15dev5.3
* Origin: FidoNet Online - http://www.fido-online.com (2:5020/400)
SEEN-BY: 46/50 50/12 203 520 450/159 186 1024 451/30 454/9 461/43 132 640
SEEN-BY: 469/999 4614/20 4616/3 4625/8 4627/10 4641/444 5000/76 5000 5001/5001
SEEN-BY: 5006/1 5007/1 5010/53 70 5011/13 5012/23 46 5015/28 5019/31 5020/86
SEEN-BY: 5020/175 194 400 545 604 639 715 758 830 892 982 1042 1057 1200 1523
SEEN-BY: 5020/1604 1665 1909 1922 2013 2020 2238 4441 5021/3 29 5022/128
SEEN-BY: 5025/3 750 5026/10 14 45 5027/12 5029/32 5030/115 217 436 473 556 966
SEEN-BY: 5030/1063 1339 1900 5034/13 5035/38 5036/1 5040/47 5042/13 5045/7
SEEN-BY: 5047/47 5049/1 5051/15 5053/16 5054/1 8 9 28 35 37 45 63 67 5055/95
SEEN-BY: 5057/1 5059/9 5060/88 5061/15 5062/1 5066/18 5070/1222 5077/70
SEEN-BY: 5080/68 1003 5081/2 5082/6 5083/21 5084/32 5085/13 5090/106 5093/27
SEEN-BY: 5095/20 5099/133 6000/1 12 6009/1
PATH: 5020/400 4441 545 5054/1 37