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