shipmonk / doctrine-mysql-index-hints
为Doctrine定制的SQL遍历器,允许在无需原生查询的情况下使用MySQL索引提示
3.1.0
2024-08-08 14:12 UTC
Requires
- php: ^8.1
- doctrine/orm: ^3.0.0
- shipmonk/doctrine-hint-driven-sql-walker: ^2.0.0
Requires (Dev)
- doctrine/collections: ^2.1
- doctrine/dbal: ^3.7
- doctrine/event-manager: ^2.0
- editorconfig-checker/editorconfig-checker: ^10.5.0
- ergebnis/composer-normalize: ^2.42
- phpstan/phpstan: ^1.11.1
- phpstan/phpstan-phpunit: ^1.4.0
- phpstan/phpstan-strict-rules: ^1.6.0
- phpunit/phpunit: ^10.5.11
- shipmonk/composer-dependency-analyser: ^1.2.1
- shipmonk/dead-code-detector: dev-master#a718a55ae62aff39ca11caa54cb9a930118af8d7
- shipmonk/phpstan-rules: ^3.0.0
- slevomat/coding-standard: ^8.15.0
This package is auto-updated.
Last update: 2024-09-13 15:22:29 UTC
README
此库提供了一种简单的方法,通过自定义SqlWalker将MySQL的索引提示集成到Doctrine查询语言编写的SELECT查询中。无需再使用原生查询。
安装
composer require shipmonk/doctrine-mysql-index-hints
简单使用
$result = $em->createQueryBuilder() ->select('u.id') ->from(User::class, 'u') ->andWhere('u.id = 1') ->getQuery() ->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, HintDrivenSqlWalker::class) ->setHint(UseIndexHintHandler::class, [IndexHint::force(User::IDX_FOO, User::TABLE_NAME)]) ->getResult();
它将产生以下SQL
SELECT u0_.id AS id_0 FROM user u0_ FORCE INDEX (IDX_FOO) WHERE u0_.id = 1
查看使用的实体(将表名和索引名放入公共常量中,以便将其绑定在一起并轻松引用是有意义的)
#[ORM\Table(name: self::TABLE_NAME)] #[ORM\Index(name: self::IDX_FOO, columns: ['id'])] #[ORM\Entity] class User { public const TABLE_NAME = 'user'; public const IDX_FOO = 'IDX_FOO'; // ... }
组合多个提示
您可能需要向MySQL提供一个可能的索引列表,或者提示它不要使用某些索引。如你所见,提示连接表同样简单。
->from(User::class, 'u') ->join('u.account', 'a') ->getQuery() ->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, HintDrivenSqlWalker::class) ->setHint(UseIndexHintHandler::class, [ IndexHint::use(Account::IDX_1, Account::TABLE_NAME), IndexHint::use(Account::IDX_2, Account::TABLE_NAME), IndexHint::ignore(Account::IDX_3, Account::TABLE_NAME), IndexHint::ignore(Account::IDX_4, Account::TABLE_NAME), ])
产生以下SQL
FROM user u0_ JOIN account a1_ IGNORE INDEX (IDX_3, IDX_4) USE INDEX (IDX_1, IDX_2) ON (...)
多次提示表连接
您可能只需要提示某些表的特定连接。只需将指定它的DQL别名作为第三个参数添加即可。
->from(User::class, 'u') ->join('u.account', 'a1') ->join('u.anotherAccount', 'a2') ->getQuery() ->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, HintDrivenSqlWalker::class) ->setHint(UseIndexHintHandler::class, [ IndexHint::use(Account::IDX_1, Account::TABLE_NAME, 'a1'), // alias needed ])
产生以下SQL
FROM user u0_ JOIN account a1_ USE INDEX (IDX_1) ON (...) JOIN account a2_ ON (...)
高级使用说明
- 它甚至适用于DQL中不存在但存在于SQL中的表!
- 例如,当选择子类时,来自类表继承的父表。
- 任何无效使用都会在运行时进行检查
- 检查表名是否存在,因此您不能意外地交换
tableName
和indexName
参数或使用不存在的DQL别名 - 忘记的提示或无效的参数也会进行检查
- 由于这些检查不能被任何静态分析工具捕获,因此建议为每个查询编写一个测试。
- 检查表名是否存在,因此您不能意外地交换
与优化器提示结合使用
从3.0.0版本开始,您可以将此库与shipmonk/doctrine-mysql-optimizer-hints结合使用。
$result = $em->createQueryBuilder() ->select('u.id') ->from(User::class, 'u') ->andWhere('u.id = 1') ->getQuery() ->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, HintDrivenSqlWalker::class) ->setHint(OptimizerHintsHintHandler::class, ['MAX_EXECUTION_TIME(1000)']) ->setHint(UseIndexHintHandler::class, [IndexHint::force(User::IDX_FOO, User::TABLE_NAME)]) ->getResult();