質問

I have nested set table (MySQL) with about 1.5 million records in it. The table structure is:

id | name | root_id | lft | rgt | level

I need to get strings, containing names of all parent records plus record name, let's call it 'full_name'. For example, it'll be

"United States, California, Los Angeles"

for "Los Angeles" record.

I may query all names for ONE record with:

SELECT parent.name
FROM location AS node,
     location AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
        AND parent.root_id=node.root_id AND node.id=:id
ORDER BY parent.level

and to build full_name using implode()

But this request works for one record only, working too slowly for several calls. So now I want to add 'full_name' to Sphinx index (or probably to MySQL directly).

QUESTIONS:

  • Is it possible to construct such sql query that will select 'full_name' for each record to put it to Sphinx index? I think this would be ideal solution for such situation.

  • I also tried to update MySQL table adding 'full_name' field, but my update requests will take several days to finish the job. Is it good idea at all? Is it possible to make this update fast enough?

  • I'm thinking, maybe I should move to PostgreSQL and use hierarchical requests (I have no experience with this database so can't be sure) ?

Thank you

役に立ちましたか?

解決

When you say you are updating your table to add the full_name field, do you mean you are running the above query for every single record individually?

Really it shouldnt be that slow, do you have proper indexes on the table?

Regardless, you can make it even quicker, by only running one actual query, to get all records. The function here: http://www.sitepoint.com/hierarchical-data-database-2/

Can easily be modified, to update all recrds. Just rather than printing out an indented list, each iteration of the loop should run an update statement. As well as maintaining the $right array, need to maintain a list of strings. Where add/remove to right add you another array at the same time.

// start with an empty $right stack
$right = array();
$names = array();

// now, retrieve whole tree
$result = mysql_query('SELECT id, name, full_name, lft, rgt FROM location ORDER BY lft ASC');

// update each row
while ($row = mysql_fetch_array($result)) {
    // only check stack if there is one
    if (count($right)>0) {
        // check if we should remove a node from the stack
        while ($right[count($right)-1]<$row['rgt']) {
            array_pop($right);
            array_pop($names);
        }
    }

    // add this node to the stack
    $right[] = $row['rgt'];
    $names[] = $row['name'];

    if (empty($row['full_name'])) {
        mysql_query("UPDATE location SET full_name='".mysql_real_escape_string(implode(', ',$names))."' WHERE id=".intval($row['id']));
    }
}

And if that is still slow, rather than updating the original table, insert the full_name (along with the id) into a new table - that doesnt have any indexes. Alter the table to add index on the id column, then run a multi-table update, to update the main table from the temporally table. This will be quicker, because its not updating the main indexes piecemeal, its doing it on one big batch.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top