Craft CMSのcraft.entries.searchは安易に使ってはいけない話

以前のエントリーで、タグ検索は

$criteria          = craft()->elements->getCriteria(ElementType::Entry);
$criteria->section = "sampleSection";
$criteria->search  = "sampleTags:test";
$entries           = $criteria->find();

こう書くよ、と記載したのですが、エントリー数が数万~数十万になると、とっても遅いのでした。
searchを使った場合、craft_searchindexテーブルが参照されるのですが、検索対象のIDが列挙されるので

SELECT * FROM craft_searchindex WHERE elementId IN (1,2,3,4,5,6,7,8 ...)

のように、WHERE IN句に、数万のIDが列挙されたりします。結果、生成されたSQLをMySQL Workbenchに貼り付けると、アプリが落ちるほど巨大なクエリーになります。
なので、正しいクエリー方法は以下のようになります。

$criteria = craft()->elements->getCriteria(ElementType::Tag);
$criteria->groupId = craft()->tags->getTagGroupByHandle('sampleGroup')->id;
$criteria->title   = 'test';
$tags = $criteria->find();
$criteria          = craft()->elements->getCriteria(ElementType::Entry);
$criteria->section = "sampleSection";
$criteria->relatedTo = ['targetElement' => $tags, 'field' => 'sampleTags'],
$entries           = $criteria->find();

relatedToを使用した場合、craft_relationsテーブルを参照した割と普通なクエリーになります。
エントリー数が20万ほどある状況だと、searchを使ったタグ検索は4秒、relatedToを使ったタグ検索は0.1秒以下でした。なので、searchはエントリー総数が少ないセクションに限定して使わないとダメそうです。
【追記】
Twigで記述する場合に

{% set entries = craft.entries.section('sampleSection').relatedTo(tags) %}

のような書き方が普通みたいな感じになっていますが、エントリー数が多い場合は、これも遅いです。
fieldを指定したほうが、場合によっては数百倍速いので、ちゃんと指定しましょう。

{% set entries = craft.entries.section('sampleSection').relatedTo({'targetElement':tags, 'field':'sampleTags'}) %}

コメント

タイトルとURLをコピーしました