Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Queries by URI with Postgres Significantly Degrade Performance #5045

mbrochstein opened this issue Oct 3, 2019 · 3 comments


Copy link

commented Oct 3, 2019


When using ->uri($uri) on an ElementQuery and a postgres database, the \craft\elements\db\ElementsQuery class forces caseInsensitive=true where clause in the query, which when processed by the \craft\helpers\Db classes' static parseParam method, adds a lower() wrapper when on postgres. This has a massive query performance implication, and cannot be turned off.

Steps to reproduce

  1. Configure CraftCMS with a PostgreSQL database
  2. Look at database queries that are produced.

Additional info

  • Craft version: 3.3
  • PHP version: 7.1
  • Database driver & version: PostgreSQL 10
  • Plugins & versions: N/A

This comment has been minimized.

Copy link

commented Oct 8, 2019

We do create an index on lower("uri"), which should be used on element queries with the uri param:

$this->createIndex($this->db->getIndexName(Table::ELEMENTS_SITES, ['uri', 'siteId']), Table::ELEMENTS_SITES, ['lower([[uri]])', 'siteId']);

I just verified that this element query:

$entry = Entry::find()

will in fact use that index; from the EXPLAIN:

->  Index Scan using "elements_sites_uri_siteId_idx" on elements_sites elements_sites_1  (cost=0.14..8.16 rows=1 width=12)

That said the index could be ignored if other conditions come before uri. Are you able to share your full element query?


This comment has been minimized.

Copy link

commented Oct 14, 2019

@brandonkelly Sure. Here it is:

  "elements_sites"."enabled" AS "enabledForSite",
  "content"."id"             AS "contentId",
        "elements"."id"       AS "elementsId",
        "elements_sites"."id" AS "elementsSitesId",
        "content"."id"        AS "contentId",
      FROM "craft_elements" "elements"
        INNER JOIN "craft_entries" "entries" ON "entries"."id" = "elements"."id"
        INNER JOIN "craft_elements_sites" "elements_sites" ON "elements_sites"."elementId" = "elements"."id"
        INNER JOIN "craft_content" "content"
          ON ("content"."elementId" = "elements"."id") AND ("content"."siteId" = "elements_sites"."siteId")
        LEFT JOIN "craft_structureelements" "structureelements"
          ON ("structureelements"."elementId" = "elements"."id") AND (EXISTS(SELECT *
                                                                             FROM "craft_structures"
                                                                             WHERE ("id" =
                                                                                   AND ("dateDeleted" IS NULL)))
      WHERE ("elements_sites"."siteId" = 1) AND ("elements"."archived" = 'f') AND (
        (("elements"."enabled" = 't') AND ("elements_sites"."enabled" = 't')) AND
        ("entries"."postDate" <= '2019-10-03 04:55:11') AND
        (("entries"."expiryDate" IS NULL) OR ("entries"."expiryDate" > '2019-10-03 04:55:11'))) AND
            ("elements"."dateDeleted" IS NULL) AND
            (lower("elements_sites"."uri") = 'the-unique-uri') AND
            ("elements_sites"."enabled" = 't') AND ("elements"."draftId" IS NULL) AND ("elements"."revisionId" IS NULL)
      ORDER BY "postDate" DESC
      LIMIT 10) "subquery"
  INNER JOIN "craft_entries" "entries" ON "entries"."id" = "subquery"."elementsId"
  INNER JOIN "craft_elements" "elements" ON "elements"."id" = "subquery"."elementsId"
  INNER JOIN "craft_elements_sites" "elements_sites" ON "elements_sites"."id" = "subquery"."elementsSitesId"
  INNER JOIN "craft_content" "content" ON "content"."id" = "subquery"."contentId"
  LEFT JOIN "craft_structureelements" "structureelements"
    ON ("structureelements"."elementId" = "subquery"."elementsId") AND
       ("structureelements"."structureId" = "subquery"."structureId")
ORDER BY "postDate" DESC;

This comment has been minimized.

Copy link

commented Oct 14, 2019

The php code is as follows:

$entryQuery = Entry::find()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
None yet
2 participants
You can’t perform that action at this time.