Aqui está a estrutura da tabela que usei para testar isso -
CREATE TABLE `test`.`pages` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`slug` varchar(45) NOT NULL,
`title` varchar(45) NOT NULL,
`content` text NOT NULL,
`parent_id` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `UQ_page_parent_id_slug` (`parent_id`,`slug`),
CONSTRAINT `FK_page_parent_id` FOREIGN KEY (`parent_id`) REFERENCES `pages` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Observe a chave exclusiva em (parent_id, slug). Isso é fundamental para obter o melhor desempenho da consulta a seguir. Testei isso com 50 mil linhas e ainda retornou em menos de 1 ms para um caminho de cinco slug -
/cms/slug-1/slug-2/slug-3/slug-4/slug-5/
Aqui está o código PHP que criei para criar uma consulta adequada -
<?php
// I will assume the rest of the url has already been stripped away
$url = '/fruits/tropical/bananas/';
// lets just make sure we don't have any leading or trailing /
$url = trim($url, '/');
// now let's split the remaining string based on the /
$aUrl = explode('/', $url);
/**
* Now let's build the query to retrieve this
*/
// this array stores the values to be bound to the query at the end
$aParams = array();
$field_list = 'SELECT p1.* ';
$tables = 'FROM pages p1 ';
$where = "WHERE p1.parent_id IS NULL AND p1.slug = ? ";
// this array stores the values to be bound to the query at the end
$aParams[] = $aUrl[0];
// if we have more than one element in our array we need to add to the query
$count = count($aUrl);
for ($i = 1; $i < $count; $i++) {
// add another table to our query
$table_alias = 'p' . ($i + 1);
$prev_table_alias = 'p' . $i;
$tables .= "INNER JOIN pages $table_alias ON {$prev_table_alias}.id = {$table_alias}.parent_id ";
// add to where clause
$where .= "AND {$table_alias}.slug = ? ";
$aParams[] = $aUrl[$i];
// overwrite the content of $field_list each time so we
// only retrieve the data for the actual page requested
$field_list = "SELECT {$table_alias}.* ";
}
$sql = $field_list . $tables . $where;
$result = $this->db->query($sql, $aParams);