| ← Сентябрь 2004 → | ||||||
|
1
|
2
|
3
|
4
|
5
|
||
|---|---|---|---|---|---|---|
|
7
|
8
|
9
|
10
|
11
|
12
|
|
|
13
|
14
|
15
|
16
|
17
|
18
|
19
|
|
20
|
21
|
22
|
23
|
24
|
25
|
26
|
|
27
|
28
|
29
|
30
|
|||
За последние 60 дней ни разу не выходила
Сайт рассылки:
http://www.sybase.ru
Открыта:
28-11-2003
Статистика
0 за неделю
Новости, работа с индексами.
| Информационный Канал Subscribe.Ru |
|
РСУБД Sybase ASA 9 - мощность, легкость и надежность Рассылка N 11 |
Здравствуйте. Представляю Вашему вниманию новый выпуск рассылки.
Содержание рассылки:
Вышло обновление EBF 1899.
iAnywhere начало опрос пользователей для сбора информации о новых возможностях, которые желательно включить в десятую версию Sybase ASA. Из уже названных возможностей можно перечислить возможность опционного создания индексов на FOREIGN KEY, материализованные представления, улучшение алгоритмов оптимизатора запросов по соединению и обработке таблиц с миллионами записей.
|
Назначение
Хранение индексов
Типы индексов
Автоматически создаваемые индексы
Кластерные индексы
Из чего могут состоять индексы
|
||
SELECT * FROM Table WHERE f_Year = 2004; SELECT * FROM Table WHERE Year(f_Date) = 2004; |
||
|
Плюсы индексов
Минусы индексов
Необходимость создания индексов
Смотрим на план запроса
Решаем, кто виноват
|
||
SELECT cc.Contract_id, Sum(ov.Value) * co.PercentValue / 100
FROM X_Contract_List cc
INNER JOIN sp_get_ContractCalcObject_Inc (@CalcDate) co
ON cc.Contract_id = co.Contract_id AND
co.CalcObject_id = @CalcObject_id AND
cc.CalcDate BETWEEN co.CreateDate AND co.c_CloseDate
INNER JOIN CalcMaskObject mo
ON co.CalcMask_id = mo.CalcMask_id AND
cc.CalcDate BETWEEN mo.CreateDate AND mo.CloseDate
INNER JOIN CalcValue_Inc ov
ON ov.CalcObject_id = mo.CalcObject_id AND
cc.Contract_id = ov.Contract_id AND
ov.CalcDate = @CalcDate
WHERE cc.CalcDate = @CalcDate
GROUP BY cc.Contract_id, co.PercentValue;
|
||
|
В данном запросе использовались: |
||
SELECT cc.Contract_id,
ov.SumValue * co.c_PercentValue / 100
FROM X_Contract_List cc
INNER JOIN sp_get_ContractCalcObject_Inc (@CalcDate) co
ON cc.Contract_id = co.Contract_id AND
co.CalcObject_id = @CalcObject_id AND
cc.CalcDate BETWEEN co.CreateDate AND co.c_CloseDate,
LATERAL (
SELECT IsNull(Sum(i.Value), 0) AS SumValue
FROM CalcValue_Inc i
WHERE i.Contract_id = cc.Contract_id AND
i.CalcDate = cc.CalcDate AND
i.CalcObject_id IN (
SELECT CalcObject_id
FROM CalcMaskObject mo
WHERE co.CalcMask_id = mo.CalcMask_id AND
cc.CalcDate BETWEEN mo.CreateDate AND mo.CloseDate AND
mo.IsActive = 1 )
) AS ov
WHERE cc.CalcDate = @CalcDate
|
||
|
Применив алгоритм внутреннего соединения подзапроса (LATERAL), который появился в ASA 9.01, фактически я сказал оптимизатору: возьми список договоров к расчету и все премии, которые на них существуют, а потом для каждой полученной записи рассчитай сумму начислений, которые входят в группу начислений, выставленной в премии договора. План запроса стал совершенно другим: исчезли TABLE SCAN и HASH таблицы, все таблицы были соединены в нужном порядке и в качестве индексов были задействованы автоматически создаваемые индексы PRIMARY KEY и FOREIGN KEY используемых в запросе таблиц. Запрос стал работать менее секунды и как оказалось необходимости создавать собственные индексы совсем не было. Выборочность индексов
Разветвлённость составных индексов
Вложенность уровней индексов
-- Корневые страницы уровня 1
-- Страницы уровня уровня 2
-- Страницы уровня уровня 3
-- Страницы листа (ссылки на физические записи)В итоге, чтобы найти нужную запись, СУБД будет вынуждена просмотреть и найти значение в дереве уровня 1, далее спуститься и обработать уровень 2, затем сделать то же самое с уровнем 3 и только потом получить ссылку на физическую запись в таблице. В итоге, можно сказать, чем меньше уровней страниц в индексе, тем быстрее он считывается и большее кол-во страниц оседает в кэше для повторного использования. На кол-во уровней в индексе влияет размер страницы, длина используемых полей и разветвлённость индекса. Посмотреть на кол-во уровней в индексах можно через системную хранимую процедуру "sa_index_levels". Влияние булевых операций сравнения на выборки по индексам
|
||
-- Неэффективный запрос SELECT * FROM Table1 WHERE Field1 = 1 OR Field2 = 1; -- Эффективный запрос SELECT * FROM Table1 WHERE Field1 = 1 UNION ALL SELECT * FROM Table1 WHERE Field2 = 1; |
||
|
|
||
CREATE INDEX idx_1 ON Table1 (Field1, Field2); SELECT * FROM Table1 WHERE Field1 <= 100 AND Field2 = 1 |
||
|
В этом примере оптимизатор запросов использует индекс idx_1, сканируя по нему только все подходящие под условия Field1, далее спуститься по уровням дерева индекса вниз до страниц листов, получит ссылки на физические записи и уже по ним отфильтрует условие "Field2 = 1". В данном случае, если поле Field2 имеет большую выборочность запроса (не путать с выборочностью индекса), т.е. охватывает большую часть записей таблицы, то эффективнее использовать индекс только по полю Field1: |
||
CREATE INDEX idx_2 ON Table1 (Field1); |
||
|
Это позволит оптимизатору просмотреть по индексу все подходящие записи для Field1 и выбрать из с таблицы, попутно фильтруя по условию для Field2. Если же Field2 имеет малую выборочность запроса, то наиболее подходящим будет составной индекс: |
||
CREATE INDEX idx_2 ON Table1 (Field2, Field1); |
||
|
В данном случае оптимизатор в этом индексе сначала
проведет поиск по условию для Field2 и уже спускаясь ниже по
уровням индекса проведет поиск по Field1. |
||
SELECT * FROM Table1 WHERE NOT (Field1 > 100); |
||
|
будет преобразован оптимизатором в запрос: |
||
SELECT * FROM Table1 WHERE Field1 <= 100; |
||
|
Если преобразование будет невозможным, то
оптимизатор будет всегда использовать полное сканирование
таблицы. Порядок определения следования полей в составных индексах
Экспериментируем без последствий
|
||
CREATE VIRTUAL INDEX v_idx_1 ON Table1 (Field1, Field2, Field3); CREATE VIRTUAL INDEX v_idx_2 ON Table1 (Field2, Field3); CREATE VIRTUAL INDEX v_idx_3 ON Table1 (Field3, Field1, Field2); SELECT * FROM Table1 WHERE Field3 = 100 AND Field1 IN (1, 2) AND Field2 > 100; |
||
|
Посмотрев план запроса мы увидели, что оптимизатор предпочел в нем использовать индекс "v_idx_3", как наиболее подходящий. Теперь можно легко закончить с экспериментами и физически создать индекс на таблицу в базе данных: |
||
CREATE INDEX idx_1 ON Table1 (Field3, Field1, Field2); |
||
|
Все созданные виртуальные индексы автоматически удалятся после завершения сессии. Так же их можно удалить оператором "DROP INDEX". |
||
| http://subscribe.ru/
http://subscribe.ru/feedback/ |
Подписан адрес: Код этой рассылки: comp.soft.db.asa9 |
Отписаться |
| В избранное | ||