powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Sybase ASA, ASE, IQ [игнор отключен] [закрыт для гостей] / ASA9.0.1 Помогите с оптимальными индексами на большой таблице
14 сообщений из 39, страница 2 из 2
ASA9.0.1 Помогите с оптимальными индексами на большой таблице
    #32668231
Фотография ASCRUS
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Если LATERAL пользоваться нельзя, то лучше тогда оставить как есть в subquery. Насчет оптимизации главного запроса: можно попробовать группы скинуть во времянку и поэксперементировать с соединениями. Тогда вполне возможно можно будет сделать составной индекс, первыми полями которого идут поля группировки, а потом поля фильтра.
...
Рейтинг: 0 / 0
ASA9.0.1 Помогите с оптимальными индексами на большой таблице
    #32668516
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ASCRUS

Вся хитрость в том, что ASA != ASE почти во всем:


В планах запросов он точно !=. Я так понял тот план, что это просто выполнение группировки.


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


В ASE тоже не нужен. Да и вообще, это ANSI -стандарт требует.
Так что не так уж и !=.

ASCRUS
2. Запрос явно является коррелированным, так как связывается по полю e164prefix с основным запросом, а так как он аггрегированный, то ASA потребовала бы включить его в группировку, что и сделано в запросе.


Там это само поле e164prefix тоже есть в списке вывода. Есть или нет e164prefix в двух таблицах подзапроса - мы не знаем. Да и вообще, что гадать ? Пусть товарищь пришлет скрипты на таблицы и запрос, и план его.
Тогда можно о чем-то говорить.

ASCRUS
3. Перенос в главное дерево, т.е. избавление от Subquery всегда увеличивает скорость работы подзапроса в ASA, только при условии, если правильно переносить :) Например в данном случае переносить запрос нужно в основной запрос не через соединение INNER JOIN, а как LATERAL (прямое внутреннее соединение, которое позволяет внутри подзапроса ссылаться на поля главного запроса, но при этом алгоритм его выполнения эффективнее, чем работа с Subquery).


Впервые слышу про такого зверя.
...
Рейтинг: 0 / 0
ASA9.0.1 Помогите с оптимальными индексами на большой таблице
    #32668565
Фотография Vovaka
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
вот скрипты, но этот подзапрос для выдергивания имени особенно не требует времени, т.к. результат группировки содержит небольшое кол-во строк

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
create table "Tel".GlobalPrefixGroup (
	ID                int primary key default autoincrement,
	PrefixGroupSetID  int references "Tel".GlobalPrefixGroupSet(ID) on update cascade on delete cascade,
        Name              char( 64 )
); 

create table "Tel".GlobalPrefix (
	ID                int primary key default autoincrement,
	PrefixGroupID     int references "Tel".GlobalPrefixGroup(ID) on update cascade on delete cascade,
        Prefix            char( 16 )
); 

а LATERAL появился только в ASA 9
...
Рейтинг: 0 / 0
ASA9.0.1 Помогите с оптимальными индексами на большой таблице
    #32668599
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ты думаешь, сервер сначала выполняет группировку, а потом подзапрос ? Далеко не факт, что так будет. Обычно происходит как раз наоборот. Что в твоем случае будет достаточно плохо.

Кстати, если это поле, которое подзапрос выводит, одно на запрос, то можно его в переменную выбрать.
...
Рейтинг: 0 / 0
ASA9.0.1 Помогите с оптимальными индексами на большой таблице
    #32668603
Фотография Vovaka
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
используя LATERAL получаетсядаже чуть хуже
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
select
e164prefix as _e164prefix, minuteprice/currencyrate as minuteprice, count(*), 
sum(billingduration)/ 60  as sbd, sum(callprice/currencyrate) as _sum, sum(callduration)/ 60  as scd 
from voip.cdr_billing, 
LATERAL (select g.name as lang from tel.globalprefixgroup g, tel.globalprefix p where g.id = prefixgroupid and prefix = e164prefix and prefixgroupsetid =  6 ) lang
where datetime between '2004-08-25' and '2004-08-26' and accounttype in ( 2 ,  3 ,  4 ,  8 ) and accountid =  33  
group by _e164prefix, minuteprice
order by  2 

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
( Plan [ Total Cost Estimate:  22 . 06509988  ] 
  ( WorkTable
    ( Sort
      ( HashGroupBy
        ( HashJoin*
          ( NestedLoopsJoin[ TRUE ]
            ( IndexScan ( GlobalPrefixGroup g ) GlobalPrefixGroupSet )
            ( IndexScan ( GlobalPrefix p ) GlobalPrefixGroup )
          )
          ( NestedLoopsJoin[ TRUE ]
            ( InList )
            ( IndexScan cdr_billing voip_cdr_billing_accountid_accounttype_datetime )
          )
        )
      )
    )
  )
)

и всем огромное спасибо
p.s. а ASCRUS еще и отдельное за статью об индексах
...
Рейтинг: 0 / 0
ASA9.0.1 Помогите с оптимальными индексами на большой таблице
    #32668640
Linas
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Index:
Код: plaintext
1.
create index test on voip.cdr_billing(accountid, datetime, e164prefix, minuteprice, currencyrate)

Query:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
select
(select first g.name as lang from tel.globalprefixgroup g, tel.globalprefix p where
g.id = prefixgroupid and prefix = e164prefix and prefixgroupsetid =  6 ) lang, 
e164prefix as _e164prefix, minuteprice/currencyrate as minuteprice, count(*), 
sum(billingduration)/ 60  as sbd, sum(callprice/currencyrate) as _sum, sum(callduration)/ 60  as scd 
from voip.cdr_billing where datetime between '2004-08-01' and '2004-08-02' and accounttype in ( 2 ,  3 ,  4 ,  8 ) and accountid =  33  
group by cdr_billing.e164prefix, cdr_billing.minuteprice, cdr_billing.currencyrate
order by cdr_billing.e164prefix

HTH, Linas
...
Рейтинг: 0 / 0
ASA9.0.1 Помогите с оптимальными индексами на большой таблице
    #32668830
Фотография ASCRUS
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Linas
Так как:
Код: plaintext
datetime between '2004-08-01' and '2004-08-02' 
то могу 100% сказать что при навязывании Вашего индекса будет на запрос ASA покажет для IndexSeek:
Код: plaintext
1.
2.
3.
4.
accountid = value
value <= datetime >= value
e164prefix *
minuteprice *
currencyrate *
а если FORCE не указывать, то она его вообще использовать не будет, так как накладно это получается.
...
Рейтинг: 0 / 0
ASA9.0.1 Помогите с оптимальными индексами на большой таблице
    #32669008
Фотография ASCRUS
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Кстати если выборка аналитического характера и может строиться с некоторым опозданием во времени, то стоит подумать о введении табличек, хранящих аггрегаты и автоматом рассчитывающихся в определенные промежутки времени (фактически аналог материализованных представлений).
...
Рейтинг: 0 / 0
ASA9.0.1 Помогите с оптимальными индексами на большой таблице
    #32669186
Linas
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Da, nepodumal pro interval. Togda problema. Mozno poprobovat tak:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
create index test1 on voip.cdr_billing(accountid, e164prefix, minuteprice, currencyrate);

select
(select first g.name as lang from tel.globalprefixgroup g, tel.globalprefix p where
g.id = prefixgroupid and prefix = e164prefix and prefixgroupsetid =  6 ) lang, 
e164prefix as _e164prefix, minuteprice/currencyrate as minuteprice, count(*), 
sum(billingduration)/ 60  as sbd, sum(callprice/currencyrate) as _sum, sum(callduration)/ 60  as scd 
from voip.cdr_billing where datetime between '2004-08-01' and '2004-08-02' and accounttype in ( 2 ,  3 ,  4 ,  8 ) and accountid =  33  
group by cdr_billing.e164prefix, cdr_billing.minuteprice, cdr_billing.currencyrate
order by cdr_billing.e164prefix
ili tak:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
create index test2 on voip.cdr_billing(accountid, datetime, e164prefix, minuteprice, currencyrate);

SELECT 
  (select first g.name as lang from tel.globalprefixgroup g, tel.globalprefix p where
            g.id = prefixgroupid and prefix = e164prefix and prefixgroupsetid =  6 ) lang, 
   e164prefix as _e164prefix, minuteprice, 
   SUM(CNT), SUM(sbd) AS sbd, SUM(_sum) AS _sum, SUM(SCD) AS scd
FROM (select
        e164prefix, minuteprice/currencyrate as minuteprice, count(*) AS CNT, 
        sum(billingduration)/ 60  as sbd, sum(callprice/currencyrate) as _sum, sum(callduration)/ 60  as scd 
      from voip.cdr_billing where datetime between '2004-08-01' and '2004-08-02' and accounttype in ( 2 ,  3 ,  4 ,  8 ) and accountid =  33  
      group by CDR_BILLING.DATETIME, cdr_billing.e164prefix, cdr_billing.minuteprice, cdr_billing.currencyrate
) AS DERIVED
GROUP BY DERIVED.e164prefix, DERIVED.minuteprice
order by DERIVED.e164prefix
...
Рейтинг: 0 / 0
ASA9.0.1 Помогите с оптимальными индексами на большой таблице
    #32669192
A
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Или подождать ASA Jasper - там будут Materialized views.
...
Рейтинг: 0 / 0
ASA9.0.1 Помогите с оптимальными индексами на большой таблице
    #32730952
bars62
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Рассматривая original QUERY я бы сказал что ету проблему надо решать несколько иначе. Учитывая то что ты делаеш выборку всего за 2 дня то максимальное колличество выбранных рекордов у тебя должно быть дге-то в пределах 800000 - ето не так уж много.
Поэтому основное решение должно быть в разбивке твоего одного QUERY на несколько этапов:

1. Создание временной таблицы:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
CREATE TABLE #billing_temp (
lang        char(64)     NULL,
_e164prefix char(16) NOT NULL,
minuteprice double   NOT NULL,
total_count integer      NULL,
sbd         double   NOT NULL,
_sum        double   NOT NULL,
scd         double   NOT NULL);
Код: plaintext
1.
CREATE INDEX billing_e164prefix_temp on #billing_temp (_e164prefix, minuteprice);


2. Основная выборка во времменую таблицу:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
INSERT INTO #billing_temp (lang, _e164prefix, minuteprice, total_count, sbd, _sum, scd)
SELECT NULL, 
       e164prefix, 
       minuteprice/currencyrate, 
       NULL, 
       sum(billingduration)/60, 
       sum(callprice/currencyrate), 
       sum(callduration)/60
FROM   voip.cdr_billing
WHERE  accountid = 543 
and    accounttype in (2, 3, 4, 8)
and    datetime >= '2004-08-25' 
and    datetime <= '2004-08-26'

Я бы заменил CLAUSE "datetime between '2004-08-25' and '2004-08-26'" на более простое выражение - SYBASE это выполняет быстрее.
Этот SELECT вернёт больше рекордов зато индексы voip_cdr_billing_accountid_accounttype и voip_cdr_billing_datetime
будут работать и ты не будеш гонять JOIN (или CORRELETED SUBQUERY) на остальные 2 таблицы (tel.globalprefixgroup i tel.globalprefix) на все миллионы рекордов.

3. Чистка

Код: plaintext
1.
2.
3.
4.
5.
6.
DELETE FROM #billing_temp
WHERE NOT EXISTS (SELECT *
                  FROM tel.globalprefixgroup g, tel.globalprefix p
                  WHERE p.prefixgroupid    = g.id
                  AND   g.prefixgroupsetid = 6
                  AND   p.prefix           = #billing_temp._e164prefix)

4. Update

Код: plaintext
1.
2.
3.
4.
5.
6.
UPDATE #billing_temp
SET lang = (SELECT g.name
            FROM tel.globalprefixgroup g, tel.globalprefix p
            WHERE p.prefixgroupid    = g.id
            AND   g.prefixgroupsetid = 6
            AND   p.prefix           = #billing_temp._e164prefix)
Код: plaintext
1.
2.
3.
4.
5.
UPDATE #billing_temp
SET total_count = (SELECT count(*)
                   FROM #billing_temp a
                   WHERE a._e164prefix = #billing_temp._e164prefix
                   AND   a.minuteprice = #billing_temp.minuteprice)


В данном случае даже не надо делать GROUP BY

5. Final SELECT

Код: plaintext
1.
2.
3.
SELECT *
FROM #billing_temp
ORDER BY 2
Код: plaintext
1.
DROP TABLE #billing_temp


Вся ета структура может быть более громоздкая зато оптимизация будет лучше и все индексы будут работать.

_________________________________
Евгений
...
Рейтинг: 0 / 0
ASA9.0.1 Помогите с оптимальными индексами на большой таблице
    #32730953
bars62
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Только сейчас обратил внимание что у тебя ASA а не ASЕ. В этом случае временную таблицу надо создавать в схеме voip и не обязательно использовать #.
...
Рейтинг: 0 / 0
ASA9.0.1 Помогите с оптимальными индексами на большой таблице
    #32747367
Dmitriy Popov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Мои 2 цента (копейки)...

Судя по Вашему запросу, независимо от того, насколько велика таблица, диапазон дата от ... до, по всей видимости - 1 месяц в 99% случаев. Это и есть то условие, которое позволит сделать Вашу таблицу "маленькой", ибо время (т.е. поле "дата транзакции") - как раз и есть та "ось" по которой ваша таблица растет.

Поэтому я бы все индексы, которые могут прийти в голову, начинал бы с этого поля.

Из того что могу предложить сам (пальцем в небо) - индекс по дате, потом по тому, что у Вас стоит в GROUP BY. Тип счета на мой взгляд не надо, он должен сам ручками перебрать.

Честно, не знаю как он group by обрабатывает, так что может ничего и не выйдет. На ваш план я еще не поглядел толком - дома гляну.
...
Рейтинг: 0 / 0
ASA9.0.1 Помогите с оптимальными индексами на большой таблице
    #32747368
Dmitriy Popov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
... замена BETWEEN ни к чему не приведет. В ASA это 100% эквивалент X >=A AND X <= B
...
Рейтинг: 0 / 0
14 сообщений из 39, страница 2 из 2
Форумы / Sybase ASA, ASE, IQ [игнор отключен] [закрыт для гостей] / ASA9.0.1 Помогите с оптимальными индексами на большой таблице
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]