Skip to content

Instantly share code, notes, and snippets.

@arnaud-lb
Created May 15, 2012 19:27
Show Gist options
  • Select an option

  • Save arnaud-lb/2704404 to your computer and use it in GitHub Desktop.

Select an option

Save arnaud-lb/2704404 to your computer and use it in GitHub Desktop.
USE INDEX / FORCE INDEX in a Doctrine2 DQL query
<?php
use UseIndexWalker;
use Doctrine\ORM\Query
$query = $em->createQuery("SELECT f FROM Foo f WHERE f.a = 1 and f.b = 2");
$query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'UseIndexWalker');
$query->setHint(UseIndexWalker::HINT_USE_INDEX, 'some_index_name');
$query->getResult();
<?php
use Doctrine\ORM\Query\SqlWalker;
/**
* Quick hack to allow adding a USE INDEX on the query
*/
class UseIndexWalker extends SqlWalker
{
const HINT_USE_INDEX = 'UseIndexWalker.UseIndex';
public function walkFromClause($fromClause)
{
$result = parent::walkFromClause($fromClause);
if ($index = $this->getQuery()->getHint(self::HINT_USE_INDEX)) {
$result = preg_replace('#(\bFROM\s*\w+\s*\w+)#', '\1 USE INDEX (' . $index . ')', $result);
}
return $result;
}
}
@gonzo-beans
Copy link
Copy Markdown

Cheers!

@multifinger
Copy link
Copy Markdown

Here is modified version of walker,
contains FIX for join-queries

http://stackoverflow.com/questions/16729011/index-hinting-in-doctrine2

@ggergo
Copy link
Copy Markdown

ggergo commented Jun 26, 2020

Here is mine that can use different indexes per DQL table aliases. Works with both createQuery and createQueryBuilder. Still a hack tho. Thx for the idea arnaud-lb!

https://github.com/ggergo/SqlIndexHintBundle
https://packagist.org/packages/ggergo/sqlindexhintbundle

@renatogcarvalho
Copy link
Copy Markdown

renatogcarvalho commented Jul 8, 2020

@ggergo Thank you for sharing your version.

The only issue I encountered is that once the query hint is added we're forced to have all the DQL aliases listed. For example, sometimes you might only want to add a hint in a JOIN clause.

Once I updated the "walkFromClause" method to the following, it worked as expected:

public function walkFromClause($fromClause): string
{
    $sql = parent::walkFromClause($fromClause);
    $hints = $this->getQuery()->getHint(self::HINT_INDEX);

    foreach ($this->getIndexHintParameters($fromClause) as $params) {
        if (!array_key_exists($params['dqlAlias'], $hints)) {
            continue;
        }
        
        $sql = $this->insertIndex($params['sqlKey'], $params['sqlTableAlias'], $hints[$params['dqlAlias']], $sql);
    }

    return $sql;
}

The difference here is the "array_key_exists()" check, which will only insert an index hint if listed.

Best,

Renato.

@ggergo
Copy link
Copy Markdown

ggergo commented Jul 9, 2020

@renatogcarvalho Thank you for noticing! I added your fix. 👍 Best regards, Gergő

@janedbal
Copy link
Copy Markdown

janedbal commented Feb 22, 2023

Another composer package: shipmonk/doctrine-mysql-index-hints

  • works even for tables nor present in DQL, but present in SQL (Single Table Inheritance)
  • supports Doctrine ORM 3
  • supports subselects

@MarionLeHerisson
Copy link
Copy Markdown

Thanks for the solution ! 🙏
Small fix : in example.php line 8, you can use UseIndexWalker::class instead of 'UseIndexWalker'. It avoids having hardcoded strings in code + it manages if the file is in a different namespace. :)

@vuon9
Copy link
Copy Markdown

vuon9 commented Sep 12, 2025

thanks, you saved me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment