С первого взгляда кто-нибудь может сказать мне, почему это действие так медленно? - PullRequest
2 голосов
/ 17 сентября 2010

Сначала эта вещь не была замечена как медленная, потому что в базе данных было не так много «узлов дерева». Теперь это действительно медленно, на первый взгляд, есть ли что-то важное, что не так с этим? Мне действительно нужно оптимизировать это, и прежде чем я переделываю все это, мне было интересно, если что-то выделяется как реальная болевая точка. Я сузил медленную часть до рекурсивной функции репозитория, которая является последней вещью в этом посте, хотя я должен определить несколько вещей, приводящих к этому ... удачи. (ПРИМЕЧАНИЕ: я не писал этого, меня просто поставили на контроль повреждений, и я пытался обернуть голову вокруг него.)

Сначала нужно понять несколько вещей:

Определение JsTreeNode:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace App.Models
{
    public class JsTreeNode
    {
        public JsTreeNode()
        {
        }

        public Attributes attributes { get; set; }
        public Data data { get; set; }
        public string state { get; set; }
        public List<JsTreeNode> children { get; set; }
    }

    public class Attributes
    {
        public string id { get; set; }
        public string rel { get; set; }
        public string mdata { get; set; }
        public string href { get; set; }
        public string complete { get; set; }
        public string edit { get; set; }
        public string title { get; set; }
        public string resourceAccountID { get; set; }
    }

    public class Data
    {
        public string title {get;set;}
        public string icon {get;set;}
    } 
}

Теперь определение таблицы TreeNodes:

CREATE TABLE [dbo].[TreeNodes](
    [TreeNodeID] [int] IDENTITY(1,1) NOT NULL,
    [TreeID] [int] NOT NULL,
    [ParentNodeID] [int] NULL,
    [ResourceID] [int] NULL,
    [NodeOrder] [int] NOT NULL,
    [NodeName] [nvarchar](250) NOT NULL,
    [CreateBy] [int] NULL,
    [CreateDate] [datetime] NULL,
    [ModifyBy] [int] NULL,
    [ModifyDate] [datetime] NULL,
    [TreeRevisionID] [int] NULL,

Определение таблицы редакций дерева ...

CREATE TABLE [dbo].[TreeRevisions](
    [TreeRevisionID] [int] IDENTITY(1,1) NOT NULL,
    [TreeID] [int] NOT NULL,
    [Notes] [text] NULL,
    [CreatedBy] [int] NOT NULL,
    [CreatedDate] [datetime] NOT NULL,
    [ModifyBy] [int] NOT NULL,
    [ModifyDate] [datetime] NOT NULL,

Теперь вот само действие Get, которое занимает 20-25 секунд, вы можете видеть там, что оно вызывает функцию репозитория, которую я определил ниже в этом потоке.

public ContentResult Get(string target,int id)
        {
            int revisionID = Convert.ToInt32(Request.QueryString["revisionID"]);
            int tempUserID = (Request.QueryString["userID"] != null)
                                 ? Convert.ToInt32(Request.QueryString["userID"])
                                 : UserID;

            var nodesList = new List<JsTreeNode>();
            if(target.Contains("tree"))
            {
                tree tree = _treeRepository.GettreeByID(id);

                var cnode = new JsTreeNode
                                       {
                                           attributes = new Attributes {id = "0",title = tree.treeName},
                                           data = new Data {title = tree.treeName},
                                           children = _treeNodesRepository.GetNodesBytreeID(id, null,revisionID),
                                           state = "open"
                                       };
                cnode.attributes.rel = "root";
                cnode.attributes.mdata = "{draggable : true}";
                nodesList.Add(cnode);
            }
            else
            {

                var trees = _CategoryRepository.getAlltreesByCategoryID(id);

                IQueryable<tree> custom;

                if(revisionID != 0)
                {
                    custom = from c in trees
                              where
                                  c.AccountID == AccountID
                              select c;
                } else
                {
                    custom = from c in trees
                             where
                                 c.AccountID == AccountID && c.PublishedRevisionID != null && c.PublishedRevisionID != 0
                             select c;
                }

                var acme = from c in trees where c.AccountID == acmeContent.acmeID select c;

                foreach (var tree in (custom.Count() > 0) ? custom : acme)
                {
                    if(revisionID == 0 && tree.PublishedRevisionID == null) continue;
                    int tempRev = (revisionID != 0) ? revisionID : (int)tree.PublishedRevisionID;

                    if(custom.Count() == 1)
                    {
                        var tempNodes = _treeNodesRepository.GetNodesBytreeID(tree.treeID, null, tempUserID, tempRev);
                        nodesList.AddRange(tempNodes);
                    }
                    else
                    {
                        var cnode = new JsTreeNode();
                        cnode.attributes = new Attributes { id = tree.treeID.ToString(), title = tree.treeName };
                        cnode.data = new Data { title = tree.treeName };
                        cnode.children = _treeNodesRepository.GetNodesBytreeID(tree.treeID, null, tempUserID, tempRev);
                        cnode.attributes.rel = "Folder";

                        nodesList.Add(cnode);
                    }
                }
            }

            var ser = new JavaScriptSerializer();
            string res = ser.Serialize(nodesList);

            return Content(res,"application/json");

        }

... и, наконец, «виновник», посмотрите, как он себя называет:

public List<JsTreeNode> GetNodesByTreeID(int TreeID, int? parentID,int userID, int revisionID)
        {

            IQueryable<UserTreeNode> TreeNodes = GetAllTreeNodesByTreeIDAndParentNodeID(TreeID, parentID,userID,revisionID);
            List<JsTreeNode> nodesList = new List<JsTreeNode>();



            foreach (UserTreeNode node in TreeNodes)
            {
                string nodeName = node.Node.NodeName.Replace("'", "&#39;");

                JsTreeNode cnode = new JsTreeNode
                                       {
                                           attributes = new Attributes
                                                            {id = node.Node.TreeNodeID.ToString(),
                                                            title = nodeName},
                                           data = new Data {title = nodeName}
                                       };

                if(node.Node.ResourceID != null)
                {
                    cnode.attributes.complete = (node.IsComplete) ? "true" : "false";
                    cnode.attributes.rel = ResourceTypes.ReturnResourceTypeName(_resourceRepository.getResourceByID(Convert.ToInt32(node.Node.ResourceID)).ResourceTypeID);
                    cnode.attributes.href = "/resource/" + node.Node.ResourceID + "?minimal=true&nodeID=" + node.Node.TreeNodeID.ToString();
                }
                else
                {
                    var nodeChildren = GetNodesByTreeID(TreeID, node.Node.TreeNodeID,userID,revisionID);
                    if (nodeChildren.Count > 0)
                        cnode.children = nodeChildren;

                    cnode.attributes.complete = "false";
                    cnode.attributes.rel = "Folder";
                }

                nodesList.Add(cnode);
            }

            return nodesList;
        }

Ответы [ 2 ]

1 голос
/ 17 сентября 2010

Таблицы, которые вы опубликовали, включают столбец идентификаторов, но эти столбцы не обозначены как первичные ключи (по крайней мере, не в показанном вами примере).

Я не могу найти ваши конструкции запросов LinqToSql, поэтому очень сложно прокомментировать оптимизацию запросов. Я подозреваю, что все это содержится в: GetAllTreeNodesByTreeIDAndParentNodeID

Запустите эти операторы индивидуально в Sql Studio:

sp_help TreeNodes
sp_help TreeRevisions

6-й набор результатов - это список индексов ... в вашем случае - этот набор результатов может быть пустым. Если у вас нет индексов, это ваша проблема № 1.

На первый взгляд, я бы рекомендовал добавить эти индексы

TreeNodes
  TreeNodeID primary key
x TreeID nonclustered index
  TreeRevisionID nonclustered index
* TreeID, ParentNodeId nonclustered index

TreeRevisions
  TreeRevisionID primary key
  TreeID nonclustered index

Тот, который отмечен *, вероятно, самый важный для вашего текущего способа запроса. Порядок столбцов важен для индекса с несколькими столбцами.

Также рассмотрите возможность извлечения всего дерева с помощью TreeId и дополнительной фильтрации / формирования в памяти. Это позволит избежать рекурсивных / повторяющихся запросов в базу данных. При таком подходе индекс, помеченный знаком x, является значимым.

1 голос
/ 17 сентября 2010

Мое лучшее предложение на этом этапе процесса - ускорить Visual Studio Profiler (отличается от Sql Profiler) и получить представление о том, какая часть процесса на самом деле занимает больше всего времени.

Если у вас нет версии VS с профилировщиком, вы можете проверить этот поиск для других профилировщиков приложений. Первый хит для asp.net.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...