How to emulate partial multicolumn (compozite) index in Oracle 11.2?












0















Big table



record (
id number primary key,

city_id number not null,
organization_id number not null,
department_id number not null, -- extra context, can be 0

renew_date date not null -- frequently updated
)


Two kind of query are used:



1.



WITH cte (city_id, organization_id, -- etc...) AS (
-- table join routine...
)
SELECT r.*
FROM record r
INNER JOIN cte t ON r.city_id = t.city_id AND r.organization_id = t.organization_id AND r.department_id = 0
WHERE -- some condition on renew_date... whatever


2.



WITH cte (city_id, organization_id, department_id, -- etc...) AS (
-- same
)
SELECT r.*
FROM record r
INNER JOIN cte t ON r.city_id = t.city_id AND r.organization_id = t.organization_id AND r.department_id = t.department_id
WHERE -- some condition on renew_date or smth else


There are rumors that partial multicolumn (compozite) index can be emulated in Oracle.
https://community.oracle.com/ideas/18213



https://blog.jooq.org/2017/01/18/how-to-emulate-partial-indexes-in-oracle/



Do i need to create a pair of some kind of hash function



CREATE OR REPLACE FUNCTION get_record_index (city_id IN NUMBER, organization_id IN NUMBER, department_id IN NUMBER)
RETURN NUMBER
DETERMINISTIC
AS
BEGIN
IF department_id <> 0 THEN RETURN NULL
ELSE RETURN no_idea_how_to_compute(city_id, organization_id);
END IF;
END;

CREATE OR REPLACE FUNCTION get_record_department_index (city_id IN NUMBER, organization_id IN NUMBER, department_id IN NUMBER)
RETURN NUMBER
DETERMINISTIC
AS
BEGIN
IF department_id = 0 THEN RETURN NULL
ELSE RETURN no_idea_how_to_compute2(city_id, organization_id, department_id);
END IF;
END;


and create two function based index?



upd:
I need smth like that



CREATE INDEX record_main_index       ON record (rayon_id, organization_id) WHERE department_id = 0;

CREATE INDEX record_department_index ON record (rayon_id, organization_id, department_id) WHERE department_id <> 0;









share|improve this question

























  • What happened when you tried?

    – mathguy
    Nov 28 '18 at 20:37











  • What would be the composite index you'd like to emulate? And you do not necessarily need to create functions to use function-based indexes in Oracle - those can actually be based on expressions too.

    – Hilarion
    Nov 28 '18 at 23:48











  • @Hilarion, CREATE INDEX record_main_index ON record (rayon_id, organization_id) WHERE department_id = 0; CREATE INDEX record_department_index ON record (rayon_id, organization_id, department_id) WHERE department_id <> 0;

    – user3665549
    Nov 29 '18 at 9:33
















0















Big table



record (
id number primary key,

city_id number not null,
organization_id number not null,
department_id number not null, -- extra context, can be 0

renew_date date not null -- frequently updated
)


Two kind of query are used:



1.



WITH cte (city_id, organization_id, -- etc...) AS (
-- table join routine...
)
SELECT r.*
FROM record r
INNER JOIN cte t ON r.city_id = t.city_id AND r.organization_id = t.organization_id AND r.department_id = 0
WHERE -- some condition on renew_date... whatever


2.



WITH cte (city_id, organization_id, department_id, -- etc...) AS (
-- same
)
SELECT r.*
FROM record r
INNER JOIN cte t ON r.city_id = t.city_id AND r.organization_id = t.organization_id AND r.department_id = t.department_id
WHERE -- some condition on renew_date or smth else


There are rumors that partial multicolumn (compozite) index can be emulated in Oracle.
https://community.oracle.com/ideas/18213



https://blog.jooq.org/2017/01/18/how-to-emulate-partial-indexes-in-oracle/



Do i need to create a pair of some kind of hash function



CREATE OR REPLACE FUNCTION get_record_index (city_id IN NUMBER, organization_id IN NUMBER, department_id IN NUMBER)
RETURN NUMBER
DETERMINISTIC
AS
BEGIN
IF department_id <> 0 THEN RETURN NULL
ELSE RETURN no_idea_how_to_compute(city_id, organization_id);
END IF;
END;

CREATE OR REPLACE FUNCTION get_record_department_index (city_id IN NUMBER, organization_id IN NUMBER, department_id IN NUMBER)
RETURN NUMBER
DETERMINISTIC
AS
BEGIN
IF department_id = 0 THEN RETURN NULL
ELSE RETURN no_idea_how_to_compute2(city_id, organization_id, department_id);
END IF;
END;


and create two function based index?



upd:
I need smth like that



CREATE INDEX record_main_index       ON record (rayon_id, organization_id) WHERE department_id = 0;

CREATE INDEX record_department_index ON record (rayon_id, organization_id, department_id) WHERE department_id <> 0;









share|improve this question

























  • What happened when you tried?

    – mathguy
    Nov 28 '18 at 20:37











  • What would be the composite index you'd like to emulate? And you do not necessarily need to create functions to use function-based indexes in Oracle - those can actually be based on expressions too.

    – Hilarion
    Nov 28 '18 at 23:48











  • @Hilarion, CREATE INDEX record_main_index ON record (rayon_id, organization_id) WHERE department_id = 0; CREATE INDEX record_department_index ON record (rayon_id, organization_id, department_id) WHERE department_id <> 0;

    – user3665549
    Nov 29 '18 at 9:33














0












0








0








Big table



record (
id number primary key,

city_id number not null,
organization_id number not null,
department_id number not null, -- extra context, can be 0

renew_date date not null -- frequently updated
)


Two kind of query are used:



1.



WITH cte (city_id, organization_id, -- etc...) AS (
-- table join routine...
)
SELECT r.*
FROM record r
INNER JOIN cte t ON r.city_id = t.city_id AND r.organization_id = t.organization_id AND r.department_id = 0
WHERE -- some condition on renew_date... whatever


2.



WITH cte (city_id, organization_id, department_id, -- etc...) AS (
-- same
)
SELECT r.*
FROM record r
INNER JOIN cte t ON r.city_id = t.city_id AND r.organization_id = t.organization_id AND r.department_id = t.department_id
WHERE -- some condition on renew_date or smth else


There are rumors that partial multicolumn (compozite) index can be emulated in Oracle.
https://community.oracle.com/ideas/18213



https://blog.jooq.org/2017/01/18/how-to-emulate-partial-indexes-in-oracle/



Do i need to create a pair of some kind of hash function



CREATE OR REPLACE FUNCTION get_record_index (city_id IN NUMBER, organization_id IN NUMBER, department_id IN NUMBER)
RETURN NUMBER
DETERMINISTIC
AS
BEGIN
IF department_id <> 0 THEN RETURN NULL
ELSE RETURN no_idea_how_to_compute(city_id, organization_id);
END IF;
END;

CREATE OR REPLACE FUNCTION get_record_department_index (city_id IN NUMBER, organization_id IN NUMBER, department_id IN NUMBER)
RETURN NUMBER
DETERMINISTIC
AS
BEGIN
IF department_id = 0 THEN RETURN NULL
ELSE RETURN no_idea_how_to_compute2(city_id, organization_id, department_id);
END IF;
END;


and create two function based index?



upd:
I need smth like that



CREATE INDEX record_main_index       ON record (rayon_id, organization_id) WHERE department_id = 0;

CREATE INDEX record_department_index ON record (rayon_id, organization_id, department_id) WHERE department_id <> 0;









share|improve this question
















Big table



record (
id number primary key,

city_id number not null,
organization_id number not null,
department_id number not null, -- extra context, can be 0

renew_date date not null -- frequently updated
)


Two kind of query are used:



1.



WITH cte (city_id, organization_id, -- etc...) AS (
-- table join routine...
)
SELECT r.*
FROM record r
INNER JOIN cte t ON r.city_id = t.city_id AND r.organization_id = t.organization_id AND r.department_id = 0
WHERE -- some condition on renew_date... whatever


2.



WITH cte (city_id, organization_id, department_id, -- etc...) AS (
-- same
)
SELECT r.*
FROM record r
INNER JOIN cte t ON r.city_id = t.city_id AND r.organization_id = t.organization_id AND r.department_id = t.department_id
WHERE -- some condition on renew_date or smth else


There are rumors that partial multicolumn (compozite) index can be emulated in Oracle.
https://community.oracle.com/ideas/18213



https://blog.jooq.org/2017/01/18/how-to-emulate-partial-indexes-in-oracle/



Do i need to create a pair of some kind of hash function



CREATE OR REPLACE FUNCTION get_record_index (city_id IN NUMBER, organization_id IN NUMBER, department_id IN NUMBER)
RETURN NUMBER
DETERMINISTIC
AS
BEGIN
IF department_id <> 0 THEN RETURN NULL
ELSE RETURN no_idea_how_to_compute(city_id, organization_id);
END IF;
END;

CREATE OR REPLACE FUNCTION get_record_department_index (city_id IN NUMBER, organization_id IN NUMBER, department_id IN NUMBER)
RETURN NUMBER
DETERMINISTIC
AS
BEGIN
IF department_id = 0 THEN RETURN NULL
ELSE RETURN no_idea_how_to_compute2(city_id, organization_id, department_id);
END IF;
END;


and create two function based index?



upd:
I need smth like that



CREATE INDEX record_main_index       ON record (rayon_id, organization_id) WHERE department_id = 0;

CREATE INDEX record_department_index ON record (rayon_id, organization_id, department_id) WHERE department_id <> 0;






oracle indexing plsql oracle11g






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 29 '18 at 9:34







user3665549

















asked Nov 28 '18 at 20:22









user3665549user3665549

265




265













  • What happened when you tried?

    – mathguy
    Nov 28 '18 at 20:37











  • What would be the composite index you'd like to emulate? And you do not necessarily need to create functions to use function-based indexes in Oracle - those can actually be based on expressions too.

    – Hilarion
    Nov 28 '18 at 23:48











  • @Hilarion, CREATE INDEX record_main_index ON record (rayon_id, organization_id) WHERE department_id = 0; CREATE INDEX record_department_index ON record (rayon_id, organization_id, department_id) WHERE department_id <> 0;

    – user3665549
    Nov 29 '18 at 9:33



















  • What happened when you tried?

    – mathguy
    Nov 28 '18 at 20:37











  • What would be the composite index you'd like to emulate? And you do not necessarily need to create functions to use function-based indexes in Oracle - those can actually be based on expressions too.

    – Hilarion
    Nov 28 '18 at 23:48











  • @Hilarion, CREATE INDEX record_main_index ON record (rayon_id, organization_id) WHERE department_id = 0; CREATE INDEX record_department_index ON record (rayon_id, organization_id, department_id) WHERE department_id <> 0;

    – user3665549
    Nov 29 '18 at 9:33

















What happened when you tried?

– mathguy
Nov 28 '18 at 20:37





What happened when you tried?

– mathguy
Nov 28 '18 at 20:37













What would be the composite index you'd like to emulate? And you do not necessarily need to create functions to use function-based indexes in Oracle - those can actually be based on expressions too.

– Hilarion
Nov 28 '18 at 23:48





What would be the composite index you'd like to emulate? And you do not necessarily need to create functions to use function-based indexes in Oracle - those can actually be based on expressions too.

– Hilarion
Nov 28 '18 at 23:48













@Hilarion, CREATE INDEX record_main_index ON record (rayon_id, organization_id) WHERE department_id = 0; CREATE INDEX record_department_index ON record (rayon_id, organization_id, department_id) WHERE department_id <> 0;

– user3665549
Nov 29 '18 at 9:33





@Hilarion, CREATE INDEX record_main_index ON record (rayon_id, organization_id) WHERE department_id = 0; CREATE INDEX record_department_index ON record (rayon_id, organization_id, department_id) WHERE department_id <> 0;

– user3665549
Nov 29 '18 at 9:33












1 Answer
1






active

oldest

votes


















1














You could add a virtual column to the table and then include that column in an index:



ALTER TABLE record ADD zero_dept_id AS (CASE department_id WHEN 0 THEN 0 END);

CREATE INDEX record_paritial_idx ON record (city_id, organization_id, zero_dept_id);


On second thought you may be wanting only the single column index below instead of the multi-column index above.



CREATE INDEX record_paritial_idx ON record (zero_dept_id);


Then in your code instead of using r.department_id = 0 you would use r.zero_dept_id = 0 to use the new index.



No guarantees that this will improve your query performance, but you can certainly give it a try.



For a multi column index that truly prunes out all the non zero department_id entries you may need more virtual columns:



ALTER TABLE record ADD zero_dept_id AS (CASE department_id WHEN 0 THEN 0 END);
ALTER TABLE record ADD zero_dept_city_id AS (CASE department_id WHEN 0 THEN city_id END);
ALTER TABLE record ADD zero_dept_org_id AS (CASE department_id WHEN 0 THEN organization_id END);

CREATE INDEX record_paritial_idx ON record (zero_dept_city_id, zero_dept_org_id, zero_dept_id);


Then in your code make the appropriate substitutions to get this:



r.zero_dept_city_id = t.city_id AND r.zero_dept_org_id = t.organization_id AND r.zero_dept_id = 0


In the last option above, you could possibly drop the zero_dept_id column since the other two virtual columns will only have values in the index when the department id is zero in which case the index would become this:



CREATE INDEX record_paritial_idx ON record (zero_dept_city_id, zero_dept_org_id);


and the query predicate would be:



r.zero_dept_city_id = t.city_id AND r.zero_dept_org_id = t.organization_id


with the department_id = 0 predicate implied by the zero_dept* virtual columns.






share|improve this answer


























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53527503%2fhow-to-emulate-partial-multicolumn-compozite-index-in-oracle-11-2%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1














    You could add a virtual column to the table and then include that column in an index:



    ALTER TABLE record ADD zero_dept_id AS (CASE department_id WHEN 0 THEN 0 END);

    CREATE INDEX record_paritial_idx ON record (city_id, organization_id, zero_dept_id);


    On second thought you may be wanting only the single column index below instead of the multi-column index above.



    CREATE INDEX record_paritial_idx ON record (zero_dept_id);


    Then in your code instead of using r.department_id = 0 you would use r.zero_dept_id = 0 to use the new index.



    No guarantees that this will improve your query performance, but you can certainly give it a try.



    For a multi column index that truly prunes out all the non zero department_id entries you may need more virtual columns:



    ALTER TABLE record ADD zero_dept_id AS (CASE department_id WHEN 0 THEN 0 END);
    ALTER TABLE record ADD zero_dept_city_id AS (CASE department_id WHEN 0 THEN city_id END);
    ALTER TABLE record ADD zero_dept_org_id AS (CASE department_id WHEN 0 THEN organization_id END);

    CREATE INDEX record_paritial_idx ON record (zero_dept_city_id, zero_dept_org_id, zero_dept_id);


    Then in your code make the appropriate substitutions to get this:



    r.zero_dept_city_id = t.city_id AND r.zero_dept_org_id = t.organization_id AND r.zero_dept_id = 0


    In the last option above, you could possibly drop the zero_dept_id column since the other two virtual columns will only have values in the index when the department id is zero in which case the index would become this:



    CREATE INDEX record_paritial_idx ON record (zero_dept_city_id, zero_dept_org_id);


    and the query predicate would be:



    r.zero_dept_city_id = t.city_id AND r.zero_dept_org_id = t.organization_id


    with the department_id = 0 predicate implied by the zero_dept* virtual columns.






    share|improve this answer






























      1














      You could add a virtual column to the table and then include that column in an index:



      ALTER TABLE record ADD zero_dept_id AS (CASE department_id WHEN 0 THEN 0 END);

      CREATE INDEX record_paritial_idx ON record (city_id, organization_id, zero_dept_id);


      On second thought you may be wanting only the single column index below instead of the multi-column index above.



      CREATE INDEX record_paritial_idx ON record (zero_dept_id);


      Then in your code instead of using r.department_id = 0 you would use r.zero_dept_id = 0 to use the new index.



      No guarantees that this will improve your query performance, but you can certainly give it a try.



      For a multi column index that truly prunes out all the non zero department_id entries you may need more virtual columns:



      ALTER TABLE record ADD zero_dept_id AS (CASE department_id WHEN 0 THEN 0 END);
      ALTER TABLE record ADD zero_dept_city_id AS (CASE department_id WHEN 0 THEN city_id END);
      ALTER TABLE record ADD zero_dept_org_id AS (CASE department_id WHEN 0 THEN organization_id END);

      CREATE INDEX record_paritial_idx ON record (zero_dept_city_id, zero_dept_org_id, zero_dept_id);


      Then in your code make the appropriate substitutions to get this:



      r.zero_dept_city_id = t.city_id AND r.zero_dept_org_id = t.organization_id AND r.zero_dept_id = 0


      In the last option above, you could possibly drop the zero_dept_id column since the other two virtual columns will only have values in the index when the department id is zero in which case the index would become this:



      CREATE INDEX record_paritial_idx ON record (zero_dept_city_id, zero_dept_org_id);


      and the query predicate would be:



      r.zero_dept_city_id = t.city_id AND r.zero_dept_org_id = t.organization_id


      with the department_id = 0 predicate implied by the zero_dept* virtual columns.






      share|improve this answer




























        1












        1








        1







        You could add a virtual column to the table and then include that column in an index:



        ALTER TABLE record ADD zero_dept_id AS (CASE department_id WHEN 0 THEN 0 END);

        CREATE INDEX record_paritial_idx ON record (city_id, organization_id, zero_dept_id);


        On second thought you may be wanting only the single column index below instead of the multi-column index above.



        CREATE INDEX record_paritial_idx ON record (zero_dept_id);


        Then in your code instead of using r.department_id = 0 you would use r.zero_dept_id = 0 to use the new index.



        No guarantees that this will improve your query performance, but you can certainly give it a try.



        For a multi column index that truly prunes out all the non zero department_id entries you may need more virtual columns:



        ALTER TABLE record ADD zero_dept_id AS (CASE department_id WHEN 0 THEN 0 END);
        ALTER TABLE record ADD zero_dept_city_id AS (CASE department_id WHEN 0 THEN city_id END);
        ALTER TABLE record ADD zero_dept_org_id AS (CASE department_id WHEN 0 THEN organization_id END);

        CREATE INDEX record_paritial_idx ON record (zero_dept_city_id, zero_dept_org_id, zero_dept_id);


        Then in your code make the appropriate substitutions to get this:



        r.zero_dept_city_id = t.city_id AND r.zero_dept_org_id = t.organization_id AND r.zero_dept_id = 0


        In the last option above, you could possibly drop the zero_dept_id column since the other two virtual columns will only have values in the index when the department id is zero in which case the index would become this:



        CREATE INDEX record_paritial_idx ON record (zero_dept_city_id, zero_dept_org_id);


        and the query predicate would be:



        r.zero_dept_city_id = t.city_id AND r.zero_dept_org_id = t.organization_id


        with the department_id = 0 predicate implied by the zero_dept* virtual columns.






        share|improve this answer















        You could add a virtual column to the table and then include that column in an index:



        ALTER TABLE record ADD zero_dept_id AS (CASE department_id WHEN 0 THEN 0 END);

        CREATE INDEX record_paritial_idx ON record (city_id, organization_id, zero_dept_id);


        On second thought you may be wanting only the single column index below instead of the multi-column index above.



        CREATE INDEX record_paritial_idx ON record (zero_dept_id);


        Then in your code instead of using r.department_id = 0 you would use r.zero_dept_id = 0 to use the new index.



        No guarantees that this will improve your query performance, but you can certainly give it a try.



        For a multi column index that truly prunes out all the non zero department_id entries you may need more virtual columns:



        ALTER TABLE record ADD zero_dept_id AS (CASE department_id WHEN 0 THEN 0 END);
        ALTER TABLE record ADD zero_dept_city_id AS (CASE department_id WHEN 0 THEN city_id END);
        ALTER TABLE record ADD zero_dept_org_id AS (CASE department_id WHEN 0 THEN organization_id END);

        CREATE INDEX record_paritial_idx ON record (zero_dept_city_id, zero_dept_org_id, zero_dept_id);


        Then in your code make the appropriate substitutions to get this:



        r.zero_dept_city_id = t.city_id AND r.zero_dept_org_id = t.organization_id AND r.zero_dept_id = 0


        In the last option above, you could possibly drop the zero_dept_id column since the other two virtual columns will only have values in the index when the department id is zero in which case the index would become this:



        CREATE INDEX record_paritial_idx ON record (zero_dept_city_id, zero_dept_org_id);


        and the query predicate would be:



        r.zero_dept_city_id = t.city_id AND r.zero_dept_org_id = t.organization_id


        with the department_id = 0 predicate implied by the zero_dept* virtual columns.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 29 '18 at 0:24

























        answered Nov 29 '18 at 0:07









        SentinelSentinel

        5,06011221




        5,06011221
































            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53527503%2fhow-to-emulate-partial-multicolumn-compozite-index-in-oracle-11-2%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            A CLEAN and SIMPLE way to add appendices to Table of Contents and bookmarks

            Calculate evaluation metrics using cross_val_predict sklearn

            Insert data from modal to MySQL (multiple modal on website)