Filter perf vs Union. Any better solution?

I have a query that I would like to simplify and still have it perform well.

The simple form of the query is as follows and I add additional filters depending on which subjects are requested,
But this performs quite poorly.

SELECT *
WHERE {
    ?s ?p ?o
    OPTIONAL {
    ?o ?pp ?oo
    }
    FILTER (
        ?s = <ex:id/12763>
        || ?s = <ex:id/15475>
        || ?s = <ex:id/26077>
        || ?s = <ex:id/10005>
        || ?s = <ex:id/12756>
        || ?s = <ex:id/29401>
        || ?s = <ex:id/14658>
        || ?s = <ex:id/29199>
        || ?s = <ex:id/53481>
        || ?s = <ex:id/41602>
        )
}

Query returned 60 results in 00:00:16.530

The Query Plan:

Projection(?s, ?p, ?o, ?pp, ?oo) [#38.4M]
`ā”€ MergeJoinOuter(?o) [#38.4M]
   +ā”€ Filter((?s = <ex:id/12763> || (?s = <ex:id/15475> || (?s = <ex:id/26077> || (?s = <ex:id/10005> || (?s = <ex:id/12756> || (?s = <ex:id/29401> || (?s = <ex:id/14658> || (?s = <ex:id/29199> || (?s = <ex:id/53481> || ?s = <ex:id/41602>)))))))))) [#0]
   ā”‚  `ā”€ Scan[OSPC](?s, ?p, ?o) [#38.4M]
   `ā”€ Scan[SPOC](?o, ?pp, ?oo) [#38.4M]

I rewrote it as follows, and it performs well, however its a huge ugly query.:

Select *
WHERE {
  
    {
	  select (<ex:id/12763> as ?s) ?p ?o 
      WHERE{ <ex:id/12763> ?p ?o.
           	OPTIONAL { ?o ?pp ?oo }
           } 
	}
  	UNION
  	{
	  select (<ex:id/15475> as ?s) ?p ?o 
      WHERE{ <ex:id/15475> ?p ?o.
           OPTIONAL { ?o ?pp ?oo }
           } 
	}
  UNION
  	{
	  select (<ex:id/26077> as ?s) ?p ?o 
      WHERE{ <ex:id/26077> ?p ?o.
           OPTIONAL { ?o ?pp ?oo }
           } 
	}
  UNION
  	{
	  select (<ex:id/10005> as ?s) ?p ?o 
      WHERE{ <ex:id/10005> ?p ?o.
           OPTIONAL { ?o ?pp ?oo }
           } 
	}
  UNION
  	{
	  select (<ex:id/12756> as ?s) ?p ?o 
      WHERE{ <ex:id/12756> ?p ?o.
           OPTIONAL { ?o ?pp ?oo }
           } 
	}
  UNION
  	{
	  select (<ex:id/29401> as ?s) ?p ?o 
      WHERE{ <ex:id/29401> ?p ?o.
           OPTIONAL { ?o ?pp ?oo }
           } 
	}
  UNION
  	{
	  select (<ex:id/14658> as ?s) ?p ?o 
      WHERE{ <ex:id/14658> ?p ?o.
           OPTIONAL { ?o ?pp ?oo }
           } 
	}
  UNION
  	{
	  select (<ex:id/29199> as ?s) ?p ?o 
      WHERE{ <ex:id/29199> ?p ?o.
           OPTIONAL { ?o ?pp ?oo }
           } 
	}
  UNION
  	{
	  select (<ex:id/53481> as ?s) ?p ?o 
      WHERE{ <ex:id/53481> ?p ?o.
           OPTIONAL { ?o ?pp ?oo }
           } 
	}
  UNION
  	{
	  select (<ex:id/41602> as ?s) ?p ?o 
      WHERE{ <ex:id/41602> ?p ?o.
           OPTIONAL { ?o ?pp ?oo }
           } 
	}
}

This produces the same results and runs quickly.

Query returned 60 results in 00:00:00.167

The Query Plan:

Projection(?s, ?p, ?o) [#60]
`ā”€ Union [#60]
   +ā”€ Projection(<ex:id/12763> AS ?s, ?p, ?o) [#6]
   ā”‚  `ā”€ MergeJoinOuter(?o) [#6]
   ā”‚     +ā”€ Sort(?o) [#6]
   ā”‚     ā”‚  `ā”€ Scan[SPOC](<ex:id/12763>, ?p, ?o) [#6]
   ā”‚     `ā”€ Scan[SC](?o, _, _) [#8.9M]
   `ā”€ Union [#54]
      +ā”€ Projection(<ex:id/15475> AS ?s, ?p, ?o) [#6]
      ā”‚  `ā”€ MergeJoinOuter(?o) [#6]
      ā”‚     +ā”€ Sort(?o) [#6]
      ā”‚     ā”‚  `ā”€ Scan[SPOC](<ex:id/15475>, ?p, ?o) [#6]
      ā”‚     `ā”€ Scan[SC](?o, _, _) [#8.9M]
      `ā”€ Union [#48]
         +ā”€ Projection(<ex:id/26077> AS ?s, ?p, ?o) [#6]
         ā”‚  `ā”€ MergeJoinOuter(?o) [#6]
         ā”‚     +ā”€ Sort(?o) [#6]
         ā”‚     ā”‚  `ā”€ Scan[SPOC](<ex:id/26077>, ?p, ?o) [#6]
         ā”‚     `ā”€ Scan[SC](?o, _, _) [#8.9M]
         `ā”€ Union [#42]
            +ā”€ Projection(<ex:id/10005> AS ?s, ?p, ?o) [#6]
            ā”‚  `ā”€ MergeJoinOuter(?o) [#6]
            ā”‚     +ā”€ Sort(?o) [#6]
            ā”‚     ā”‚  `ā”€ Scan[SPOC](<ex:id/10005>, ?p, ?o) [#6]
            ā”‚     `ā”€ Scan[SC](?o, _, _) [#8.9M]
            `ā”€ Union [#36]
               +ā”€ Projection(<ex:id/12756> AS ?s, ?p, ?o) [#6]
               ā”‚  `ā”€ MergeJoinOuter(?o) [#6]
               ā”‚     +ā”€ Sort(?o) [#6]
               ā”‚     ā”‚  `ā”€ Scan[SPOC](<ex:id/12756>, ?p, ?o) [#6]
               ā”‚     `ā”€ Scan[SC](?o, _, _) [#8.9M]
               `ā”€ Union [#30]
                  +ā”€ Projection(<ex:id/29401> AS ?s, ?p, ?o) [#6]
                  ā”‚  `ā”€ MergeJoinOuter(?o) [#6]
                  ā”‚     +ā”€ Sort(?o) [#6]
                  ā”‚     ā”‚  `ā”€ Scan[SPOC](<ex:id/29401>, ?p, ?o) [#6]
                  ā”‚     `ā”€ Scan[SC](?o, _, _) [#8.9M]
                  `ā”€ Union [#24]
                     +ā”€ Projection(<ex:id/14658> AS ?s, ?p, ?o) [#6]
                     ā”‚  `ā”€ MergeJoinOuter(?o) [#6]
                     ā”‚     +ā”€ Sort(?o) [#6]
                     ā”‚     ā”‚  `ā”€ Scan[SPOC](<ex:id/14658>, ?p, ?o) [#6]
                     ā”‚     `ā”€ Scan[SC](?o, _, _) [#8.9M]
                     `ā”€ Union [#18]
                        +ā”€ Projection(<ex:id/29199> AS ?s, ?p, ?o) [#6]
                        ā”‚  `ā”€ MergeJoinOuter(?o) [#6]
                        ā”‚     +ā”€ Sort(?o) [#6]
                        ā”‚     ā”‚  `ā”€ Scan[SPOC](<ex:id/29199>, ?p, ?o) [#6]
                        ā”‚     `ā”€ Scan[SC](?o, _, _) [#8.9M]
                        `ā”€ Union [#12]
                           +ā”€ Projection(<ex:id/53481> AS ?s, ?p, ?o) [#6]
                           ā”‚  `ā”€ MergeJoinOuter(?o) [#6]
                           ā”‚     +ā”€ Sort(?o) [#6]
                           ā”‚     ā”‚  `ā”€ Scan[SPOC](<ex:id/53481>, ?p, ?o) [#6]
                           ā”‚     `ā”€ Scan[SC](?o, _, _) [#8.9M]
                           `ā”€ Projection(<ex:id/41602> AS ?s, ?p, ?o) [#6]
                              `ā”€ MergeJoinOuter(?o) [#6]
                                 +ā”€ Sort(?o) [#6]
                                 ā”‚  `ā”€ Scan[SPOC](<ex:id/41602>, ?p, ?o) [#6]
                                 `ā”€ Scan[SC](?o, _, _) [#8.9M]

Is there a better way to do this?

I may have found a solution to this issue.

Here is my new query.

Query returned 60 results in 00:00:00.154


SELECT *
WHERE {
  
    VALUES ?s { 
    	<ex:id/12763>
        <ex:id/15475>
        <ex:id/26077>
        <ex:id/10005>
        <ex:id/12756>
        <ex:id/29401>
        <ex:id/14658>
        <ex:id/29199>
        <ex:id/53481>
        <ex:id/41602>
    }
    
    ?s ?p ?o
    OPTIONAL {
      ?o ?pp ?oo
    }
}
The Query Plan:

Projection(?s, ?p, ?o, ?pp, ?oo) [#0]
`ā”€ MergeJoinOuter(?o) [#0]
   +ā”€ Sort(?o) [#0]
   ā”‚  `ā”€ DirectHashJoin(?s) [#0]
   ā”‚     +ā”€ VALUES (?s) {
   ā”‚     ā”‚  +ā”€ ( ex:id/12763 )
   ā”‚     ā”‚  +ā”€ ( ex:id/15475 )
   ā”‚     ā”‚  +ā”€ ( ex:id/26077 )
   ā”‚     ā”‚  +ā”€ ( ex:id/10005 )
   ā”‚     ā”‚  +ā”€ ( ex:id/12756 )
   ā”‚     ā”‚  +ā”€ ( ex:id/29401 )
   ā”‚     ā”‚  +ā”€ ( ex:id/14658 )
   ā”‚     ā”‚  +ā”€ ( ex:id/29199 )
   ā”‚     ā”‚  +ā”€ ( ex:id/53481 )
   ā”‚     ā”‚  `ā”€ ( ex:id/41602 )
   ā”‚     ā”‚  }
   ā”‚     `ā”€ Scan[SPOC](?s, ?p, ?o) [#38.7M]
   `ā”€ Scan[SPOC](?o, ?pp, ?oo) [#38.7M]

Yes, VALUES is the right thing to use here. Or you can use FILTER (s IN (...)) which will be transformed into VALUES by the query optimizer. In the future, query optimizer will do this transformation for || filters too.

Best,
Evren

1 Like

Thanks for the info, and Iā€™m looking forward to the improved query optimizer.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.