← Сентябрь 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 |
Отписаться |
В избранное | ||