>> I am having problem with the query which is constructed like this:
>>
>> SELECT S.Column1, S.Column2, STORED_PROC.Column1, STORED_PROC.Column2
>>FROM TABLE SomeTable S
>> LEFT JOIN STORED_PROC(S.UniqueID) ON 1=1
>> WHERE S.Data>= '01.07.2012' AND S.Data<='09.07.2012'
>>
>> Table SomeTable does not have much records, like few hundred, however 
>> procedure STORED_PROC is
>> doing some calculations on a table which is having 40 million of records. 
>> The calculations are
>> simply a SUM() of columns of some records which foreign key is equal to 
>> S.UniqueID.
>>
>> My problem is that when I run this query for the first time it takes a lot 
>> of time to execute
>> and hard disk activity is veary heavy. When I run it for the second time it 
>> executes much more
>> faster and hard disk activity is unnoticeable.
>
> Aggregate functions can be time consuming on databases using MVCC like 
> Firebird. The database has to look at the individual records (and probably 
> several versions of some of them - depending on your use of updates and 
> transactions). I've no clue why things are 14 times slower on first execution 
> than later executions, but maybe Thomas or someone else might answer that 
> question when we get to learn more about your system.
>
> However, one way that sometimes may speed up queries like yours (it cannot be 
> used in all situations, we don't know enough about your database to tell 
> whether it can be useful for you or not), is to use aggregate tables that are 
> populated through triggers. E.g.
>
> CREATE TABLE AggregateTable
> (MyPK      INTEGER PRIMARY KEY, /* Have a generator and trigger to fill this 
> */
>   UNIQUE_ID INTEGER,
>   MySum     INTEGER);
>
> INSERT INTO AggregateTable(UNIQUE_ID, MySum) /* A one time operation */
> SELECT UNIQUE_ID, SUM(MyField)
> FROM FortyMillionsRecordsTable
> GROUP BY 1;
>
> CREATE TRIGGER InsertAggregate FOR FortyMillionsRecordsTable ACTIVE AFTER 
> INSERT
> AS BEGIN
>    INSERT INTO AggregateTable(UNIQUE_ID, MySum)
>    VALUES(new.UNIQUE_ID, new.MyField);
> END;
>
> CREATE TRIGGER DeleteAggregate FOR FortyMillionsRecordsTable ACTIVE AFTER 
> DELETE
> AS BEGIN
>    INSERT INTO AggregateTable(UNIQUE_ID, MySum)
>    VALUES(old.UNIQUE_ID, -old.MyField);
> END;
>
> CREATE TRIGGER UpdateAggregate FOR FortyMillionsRecordsTable ACTIVE AFTER 
> UPDATE
> AS BEGIN
>    IF (old.UNIQUE_ID IS DISTINCT FROM new.UNIQUE_ID OR old.MySum IS DISTINCT 
> FROM new.MySum) THEN
>    BEGIN
>      INSERT INTO AggregateTable(UNIQUE_ID, MySum)
>      VALUES(old.UNIQUE_ID, -old.MyField);
>      INSERT INTO AggregateTable(UNIQUE_ID, MySum)
>      VALUES(new.UNIQUE_ID, new.MyField);
>    END
> END;
>
> Then, modify your procedure to do SUM(AggregateTable) rather than 
> SUM(FortyMillionsRecordsTable), and regularly (it might be daily, it might be 
> monthly depending on how often updates happens) do something like:
>
> EXECUTE BLOCK AS
>    DECLARE VARIABLE I INTEGER;
> BEGIN
>    I = SELECT GEN_ID(AggregateTableMyPK, 0);
>
>    INSERT INTO AggregateTable(UNIQUE_ID, MySum)
>    SELECT UNIQUE_ID, SUM(MyField)
>    FROM AggregateTable
>    WHERE MyPK<  :I;
>
>    DELETE FROM AggregateTable
>    WHERE MyPK<  :I;
> END

Aggregate tables (materialized views), hmm lovely. One of my preferred 
topic from the past: ;-)

http://www.ibphoenix.com/resources/documents/general/doc_1



-- 
With regards,
Thomas Steinmaurer (^TS^)
Firebird Technology Evangelist

http://www.upscene.com/

Do you care about the future of Firebird? Join the Firebird Foundation:
http://www.firebirdsql.org/en/firebird-foundation/

Reply via email to