Hi,

I just tried to use the 'Wikitools' module on a medium/large D6 site (~ 55,000 nodes), because I need unique page titles for a wiki-like behaviour. Enabling the module worked fine, but accessing the settings page rendered impossible - the page simply wouldn't load.

In MySQL in noticed continous and heavy activity, including log-running queries that seems not to finish even after hours. During this time, the server load peaked between 8 and 12 (dual core server) continously. After disabling Wikitools, this spook disappeared. Drupal's watchdog log didn't record anything noteworthy related to Wikitools.

I have 'Wikitools' running on smaller sites, so basically it works; however, this particular problem seems to be related to the size of the website, the number of node or the size of taxonomy (I don't know what queries Wikitools is running when the settings page is being accessed).

I'm setting this issue to 'critical' because the described behaviour heavily limits the module's use and might even cause problems in shared hosting environments. Please feel free to change this if you feel that it's not appropriate.

Thanks & greetings, -asb

CommentFileSizeAuthor
#6 679858-6.patch2.83 KBjpmckinney
#5 679858-5.patch2.83 KBjpmckinney

Comments

cwgordon7’s picture

I can definitely see how that query would be very very slow on a large site. It will run at O(n2), since it's joining the node table to itself. (For a site with 55,000 nodes, it would need to make 3,025,000,000 comparisons). I don't pretend to be an expert on optimizing queries, quite the opposite, so if anyone else has better suggestions or would like to comment on the viability of these approaches, I'd appreciate it. Possible solutions I see:

- Remove the query on the admin settings page, and only run it if users visit the duplicate titles page.
- Add a limit to the query - only select 10 items at a time, using pager query? I don't know if this would necessarily help if there actually aren't any duplicates.
- Load *all* the nodes. While this is costly, it shouldn't be too hard, relatively speaking, to load all 55000 node titles into PHP. Then we could use a more efficient algorithm to sort them and check for duplicates that way. As far as I know, it's not possible to index mysql columns based on the LOWER() results of that column, so the database engine itself can't be efficient about it.
- Run the query in parts from the batch API. This way, even if it takes a long, long time, at least it will finish, and then we can cache the result we get.
- Just remove the ability to list all duplicates, but instead, display a notice to an administrator if they visit the node with a duplicate title.

Thoughts?

asb’s picture

Hi,

thanks for your reply! At least it explains what I was experiencing, even if I don't understand what this "O(n²)" query does; as a total amateur, I'd probably try to make a temporary table, copy the page titles and nids over, make the title field distinct and collect what's falling out in a second table with references to the nids. However, for sure there are reasons why this won't work.

My next thought from the "idiot user point of view" would be to have a look at MediaWiki's page table; even if the MediaWiki database schema is much simpler than Drupal's, their concepts might be worth a look (at least it is proven that they can handle millions of wiki pages, including page revisions, templates/includes, and backlinks).

As far as I understand it, they prevent the problem from the beginning because they don't allow duplicate pages at all with MediaWiki::checkInitialQueries(), Manual:index.phpand Manual:Title.php (however, only page_id is unique, like Drupal's $nid; MediaWiki's page_title is a simple varchar(255)); so this problem would only occur if a) two MediaWiki databases were to be merged, and indeed Google doesn't know much about such attempts, or b) if one article would be moved between two namespaces (Manual:Using custom namespaces, section "Dealing with existing pages").

Their approach to resolve such cases is aa) to manually fix the affected pages/page titles or bb) to use the "Namespace title conflict cleanup script" namespaceDupes.php (couldn't find a documentation for this, the code is in their SVN repository). The duplicate finding part is, I believe:

    /**
     * Find pages in mainspace that have a prefix of the new namespace
     * so we know titles that will need migrating
     * @param $ns int Namespace id (id for new namespace?)
     * @param $name String Prefix that is being made a namespace
     */
    private function getConflicts( $ns, $name ) {
        $page  = 'page';
        $table = $this->db->tableName( $page );

        $prefix     = $this->db->strencode( $name );
        $encNamespace = $this->db->addQuotes( $ns );

        $titleSql = "TRIM(LEADING '$prefix:' FROM {$page}_title)";
        if( $ns == 0 ) {
            // An interwiki; try an alternate encoding with '-' for ':'
            $titleSql = $this->db->buildConcat( array( "'$prefix-'", $titleSql ) );
        }
                                     
        $sql = "SELECT {$page}_id    AS id,
                       {$page}_title AS oldtitle,
                       $encNamespace AS namespace,
                       $titleSql     AS title
                  FROM {$table}
                 WHERE {$page}_namespace=0
                   AND {$page}_title " . $this->db->buildLike( $name . ':', $this->db->anyString() );

        $result = $this->db->query( $sql, __METHOD__ );

        $set = array();
        foreach( $result as $row ) {
            $set[] = $row;
        }
        $this->db->freeResult( $result );

        return $set;
    }

If this "O(n²)" query is a one time operation, an offline (like MediaWiki's maintenance) script might be as well suited as a Batch API operation. Maybe at leasts parts of namespaceDupes.php can be adapted for this?

Greetings, -asb

BenK’s picture

Subscribing...

asb’s picture

I just was bitten again by this issue on another site. After importing a few hundred images into image nodes, I reached 33,633 nodes and ./admin/settings/wikitools became inaccessible again. That's the query it seems to be running:

EXPLAIN SELECT COUNT(DISTINCT(n1.nid)) FROM node n1, node n2 WHERE LOWER(REPLACE(REPLACE(n1.title, "_", " "), "-", " ")) = LOWER(REPLACE(REPLACE(n2.title, "_", " "), "-", " ")) AND n1.nid != n2.nid AND n1.type IN('artikel','blog','etappe','image','nachricht','poi','produkt','region','reisebeschreibung','ressource','rezension','seite','poll') AND n2.type IN('artikel','blog','etappe','image','nachricht','poi','produkt','region','reisebeschreibung','ressource','rezension','seite','poll'):

Is there any progress on this issue, or maybe there is a workaround? Since I can't access the 'wikitools' configuration page anymore, I can't disable the duplicate checking; would it be safe to just disable the module?

Thanks & greetings, -asb

jpmckinney’s picture

Version: 6.x-1.2 » 6.x-1.x-dev
Status: Active » Needs review
StatusFileSize
new2.83 KB

Ok, I think we can all agree that this query should not be run anytime someone wants to configure wikitools. I removed the query from the settings page and put a link to the duplicate content page in the help message.

jpmckinney’s picture

StatusFileSize
new2.83 KB

Forgot a parenthesis.

jpmckinney’s picture

Status: Needs review » Fixed

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.