2016-03-02 180 views
1

對不起,這個問題。我不是一個好程序員joomla的Mysql查詢花費很長時間

Everything執行得很好,菜單項很少。但有14K個菜單項。我堅持這個查詢。當我嘗試訪問時發生這種情況

administrator/index.php?option=com_modules&view=module&layout=edit&id=97 有什麼方法可以改變查詢?

查詢

SELECT a.id AS value, 
     a.title AS text, 
     a.alias, 
     a.level, 
     a.menutype, 
     a.type, 
     a.template_style_id, 
     a.checked_out 
FROM gjb0e_menu AS a 
     LEFT JOIN `gjb0e_menu` AS b 
       ON a.lft > b.lft 
       AND a.rgt < b.rgt 
WHERE a.published != -2 
GROUP BY a.id, 
      a.title, 
      a.alias, 
      a.level, 
      a.menutype, 
      a.type, 
      a.template_style_id, 
      a.checked_out, 
      a.lft 
ORDER BY a.lft ASC 

PHP代碼

require_once JPATH_ADMINISTRATOR . '/components/com_menus/helpers/menus.php'; 
$menuTypes = MenusHelper::getMenuLinks(); 

 <ul class="treeselect"> 
      <?php foreach ($menuTypes as &$type) : ?> 
      <?php if (count($type->links)) : ?> 
       <?php $prevlevel = 0; ?> 
       <li> 
        <div class="treeselect-item pull-left"> 
         <label class="pull-left nav-header"><?php echo $type->title; ?></label></div> 
       <?php foreach ($type->links as $i => $link) : ?> 
        <?php 
        if ($prevlevel < $link->level) 
        { 
         echo '<ul class="treeselect-sub">'; 
        } elseif ($prevlevel > $link->level) 
        { 
         echo str_repeat('</li></ul>', $prevlevel - $link->level); 
        } else { 
         echo '</li>'; 
        } 
        $selected = 0; 
        if ($this->item->assignment == 0) 
        { 
         $selected = 1; 
        } elseif ($this->item->assignment < 0) 
        { 
         $selected = in_array(-$link->value, $this->item->assigned); 
        } elseif ($this->item->assignment > 0) 
        { 
         $selected = in_array($link->value, $this->item->assigned); 
        } 
        ?> 
         <li> 
          <div class="treeselect-item pull-left"> 
           <input type="checkbox" class="pull-left" name="jform[assigned][]" id="<?php echo $id . $link->value; ?>" value="<?php echo (int) $link->value; ?>"<?php echo $selected ? ' checked="checked"' : ''; ?> /> 
           <label for="<?php echo $id . $link->value; ?>" class="pull-left"><?php echo $link->text; ?> <span class="small"><?php echo JText::sprintf('JGLOBAL_LIST_ALIAS', $this->escape($link->alias));?></span></label> 
          </div> 
        <?php 

        if (!isset($type->links[$i + 1])) 
        { 
         echo str_repeat('</li></ul>', $link->level); 
        } 
        $prevlevel = $link->level; 
        ?> 
        <?php endforeach; ?> 
       </li> 
       <?php endif; ?> 
      <?php endforeach; ?> 
     </ul> 

這裏是其產生查詢的功能。

public static function getMenuLinks($menuType = null, $parentId = 0, $mode = 0, $published = array(), $languages = array()) 
{ 
    $db = JFactory::getDbo(); 
    $query = $db->getQuery(true) 
     ->select('a.id AS value, a.title AS text, a.alias, a.level, a.menutype, a.type, a.template_style_id, a.checked_out') 
     ->from('#__menu AS a') 
     ->join('LEFT', $db->quoteName('#__menu') . ' AS b ON a.lft > b.lft AND a.rgt < b.rgt'); 

    // Filter by the type 
    if ($menuType) 
    { 
     $query->where('(a.menutype = ' . $db->quote($menuType) . ' OR a.parent_id = 0)'); 
    } 

    if ($parentId) 
    { 
     if ($mode == 2) 
     { 
      // Prevent the parent and children from showing. 
      $query->join('LEFT', '#__menu AS p ON p.id = ' . (int) $parentId) 
       ->where('(a.lft <= p.lft OR a.rgt >= p.rgt)'); 
     } 
    } 

    if (!empty($languages)) 
    { 
     if (is_array($languages)) 
     { 
      $languages = '(' . implode(',', array_map(array($db, 'quote'), $languages)) . ')'; 
     } 

     $query->where('a.language IN ' . $languages); 
    } 

    if (!empty($published)) 
    { 
     if (is_array($published)) 
     { 
      $published = '(' . implode(',', $published) . ')'; 
     } 

     $query->where('a.published IN ' . $published); 
    } 

    $query->where('a.published != -2') 
     ->group('a.id, a.title, a.alias, a.level, a.menutype, a.type, a.template_style_id, a.checked_out, a.lft') 
     ->order('a.lft ASC'); 

    // Get the options. 
    $db->setQuery($query); 

    try 
    { 
     $links = $db->loadObjectList(); 
    } 
    catch (RuntimeException $e) 
    { 
     JError::raiseWarning(500, $e->getMessage()); 

     return false; 
    } 

    if (empty($menuType)) 
    { 
     // If the menutype is empty, group the items by menutype. 
     $query->clear() 
      ->select('*') 
      ->from('#__menu_types') 
      ->where('menutype <> ' . $db->quote('')) 
      ->order('title, menutype'); 
     $db->setQuery($query); 

     try 
     { 
      $menuTypes = $db->loadObjectList(); 
     } 
     catch (RuntimeException $e) 
     { 
      JError::raiseWarning(500, $e->getMessage()); 

      return false; 
     } 

     // Create a reverse lookup and aggregate the links. 
     $rlu = array(); 

     foreach ($menuTypes as &$type) 
     { 
      $rlu[$type->menutype] = & $type; 
      $type->links = array(); 
     } 

     // Loop through the list of menu links. 
     foreach ($links as &$link) 
     { 
      if (isset($rlu[$link->menutype])) 
      { 
       $rlu[$link->menutype]->links[] = & $link; 

       // Cleanup garbage. 
       unset($link->menutype); 
      } 
     } 

     return $menuTypes; 
    } 
    else 
    { 
     return $links; 
    } 
+2

補充解釋,並且隨着模式 – 2016-03-02 04:56:56

+1

那剩下>加入和<將是極其緩慢的崗位。我們真的不知道你的數據或你想做什麼,但你必須簡化這個連接。 – rgvassar

回答

1

您可以簡單地刪除連接。我很確定這個連接在你的查詢中絕對沒有影響,而且會更快。您可以嘗試在有或沒有連接的情況下直接在數據庫中運行查詢,以驗證結果是否相同。

我不確定這個連接的目的是做什麼,但我想這是程序員試圖實現的某些功能的一些剩餘部分,但實現的方式不同或丟棄,留下無用的連接。

這種分層表的結構就是這樣來防止這種連接。你有一個lft和一個rgt值,並且任何在lft和rgt之間的項目都是一個子項目。另外你還有一個級別值,告訴你樹中的值有多深。因此,要選擇一個項目的所有的孩子,你可以這樣做:

select * where lft>item.lft and rgt>item.rgt 

要選擇項目的唯一的直接後裔,就

select * where lft>item.lft and rgt>item.rgt and level=item.level+1 

在數據庫中的結構是有點難以維持,需要用於更新數據的特殊功能,但快速搜索和提取數據。

所以,你getMenuLinks() - 函數應該開始像

public static function getMenuLinks($menuType = null, $parentId = 0, 
    $mode = 0, $published = array(), $languages = array()) 
{ 
    $db = JFactory::getDbo(); 
    $query = $db->getQuery(true) 
    ->select('a.id AS value, a.title AS text, a.alias, a.level, 
     a.menutype, a.type, a.template_style_id, a.checked_out') 
    ->from('#__menu AS a'); 

    // Filter by the type 
    if ($menuType) 
    ... 
+0

tQQ。先生問題解決了 –