Sci数据库检索方法:从数据库中检索数据的最快方法

我正在使用 C # 和 Sql Server 2008 的 ASP.NET 项目。

我有三个表:

Users DataFields DataField Values

每个用户对每个数据字段都有一个特定的值,该值存储在 DataFieldsValues 中。

现在我想显示一个如下所示的报告:

enter image description here

我已经创建了对象UserDataField。在 DataField 对象中,有 Methodstring GetValue(User user),其中我获取某个用户的字段的值。

然后我有用户列表List<User> users和 DataFields 列表List<DataField> fields,我执行以下操作:

string html = string.Empty;
html += "<table>";
html += "<tr><th>Username</th>";
foreach (DataField f in fields)
{
   html += "<th>" + f.Name + "</th>";
}
html += "</tr>"
foreach (User u in users)
{
   html += "<tr><td>" + u.Username + "</td>"
   foreach (DataField f in fields)
   {
      html += "<td>" + f.GetValue(u) + "</td>";
   }
   html += "</tr>"
}
Response.Write(html);

这工作正常,但是非常慢,我说的是 20 个用户和 10 个数据字段,在性能方面有没有更好的方法来实现这一点?

编辑:对于类中的每个参数,我使用以下方法检索值:

public static string GetDataFromDB(string query)
{
    string return_value = string.Empty;
    SqlConnection sql_conn;
    sql_conn = new SqlConnection(ConfigurationManager.ConnectionStrings["XXXX"].ToString());
    sql_conn.Open();
    SqlCommand com = new SqlCommand(query, sql_conn);
    //if (com.ExecuteScalar() != null)
    try
    {
        return_value = com.ExecuteScalar().ToString();
    }
    catch (Exception x)
    {
    }
    sql_conn.Close();
    return return_value;
} 

例如:

public User(int _Id)
{
this.Id = _Id
this.Username = DBAccess.GetDataFromDB("select Username from Users where Id=" + this.Id)
 //...
}
23

这里有 2 个建议会有所帮助。第一个建议是什么会显著提高你的表现。第二个建议也会有所帮助,虽然可能不会让你的应用程序在你的情况下更快。

建议1

你经常调用方法GetDataFromDB(string query)。这很糟糕,因为你每次都创建一个新的 SqlConnection 和 SqlCommand。这需要时间和资源。另外,如果有任何网络延迟,那乘以你正在进行的调用次数。所以这只是一个坏主意。

我建议您调用该方法一次,并让它填充一个集合,如Dictionary<int, string>,以便您可以从用户 ID 键快速查找您的用户名值。

这样地:

// In the DataField class, have this code.
// This method will query the database for all usernames and user ids and
// return a Dictionary<int, string> where the key is the Id and the value is the 
// username. Make this a global variable within the DataField class.
Dictionary<int, string> usernameDict = GetDataFromDB("select id, username from Users");
// Then in the GetValue(int userId) method, do this:
public string GetValue(int userId)
{
    // Add some error handling and whatnot. 
    // And a better name for this method is GetUsername(int userId)
    return this.usernameDict[userId];
}

建议2

这里是另一种可以改进的方法,虽然在这种情况下稍微使用StringBuilder类。有显著的性能提升(这里是一个概述:http://support.microsoft.com/kb/306822)。

SringBuilder sb = new StringBuilder();
sb.Append("<table><tr><th>Username</th>");
foreach (DataField f in fields)
{
    sb.Append("<th>" + f.Name + "</th>");
}
// Then, when you need the string
string html = sb.ToString();

让我知道,如果你需要一些更多的澄清,但你所要求的是非常可行的。我们可以解决这个问题!

如果您进行这 2 个简单的更改,您将拥有出色的性能,我保证。

19

您选择的数据库设计名为Entity-Attribute-Value,该设计因其性能问题而闻名。SQL Server 团队发布了一份,以获取有关 E 设计的指导,请参阅Best Practices for Semantic Data Modeling for Performance and Scalability

唉,你已经有了设计,你现在能做些什么呢?重要的是将对 dB 的 miriad 调用减少到一个单一的调用,并执行一个单一的面向集合的语句来检索数据。游戏的名称是Table Valued Parameters

declare @users as UsersType;
insert into @users (UserId) values (7), (42), (89);
select ut.Id, 
  ut.Username, 
  df.Name as DataFieldName, 
  dfv.Value
from Users ut
join @users up on ut.Id = up.UserId
join DataFieldValues dfv on ut.Id = dfv.UserId
join DataFields df on dfv.DataFieldId = df.Id
order by ut.Id;

有关完整示例,请参阅此SqlFiddle

虽然严格来说,可以使用PIVOT运算符在您想要的形状上检索结果(数据字段名称转置为列名称),但我强烈建议不要这样做。PIVOT 本身是一个性能泥潭,但是当您添加所需结果集的动态特性时,基本上不可能将其删除。传统的结果集 ID 由每行属性组成,这保证了用户之间的关联顺序是微不足道的,

14

这是缓慢的,因为在引擎盖下,您正在对数据库进行 20 x 10 = 200 次查询。正确的方法是一次加载所有内容。

您应该发布有关加载数据方式的一些详细信息。如果您使用的是 Entity Framework,则应该使用名为 Eager Loading using Include 命令。

// Load all blogs and related posts
var blogs1 = context.Blogs
                      .Include(b => b.Posts)
                      .ToList();

一些示例可以在这里找到:http://msdn.microsoft.com/en-us/data/jj574232.aspx

编辑:

看来你没有使用.NET Framework 给你的工具。这些天你不必为像你这样的简单场景做自己的数据库访问。另外,你应该避免像你这样连接字符串 HTML。

我建议你重新设计你的应用程序使用现有的 ASP.NET 控件和实体框架。

这是一个示例,其中包含一步一步的说明:http://www.codeproject.com/Articles/363040/An-Introduction-to-Entity-Framework-for-Absolute-B

6

正如 Remus Rusanu 所说,您可以通过使用 PIVOT 关系运算符以所需的格式获取所需的数据,就 PIVOT 的性能而言,我发现这将取决于您的表的索引以及数据集的可变性和大小。我非常有兴趣从他那里听到更多关于他对 PIVOT 的看法的信息,因为我们都在这里学习。关于 PIVOT 的讨论非常热烈。

如果 DataFields 表是一个静态集,那么您可能不需要担心动态生成 SQL,您可以自己构建一个存储过程;如果它确实有所不同,您可能需要采取动态 SQL(here is an excellent article on this)的性能冲击或使用不同的方法。

除非您进一步需要数据,否则尝试将返回的集合保持为显示所需的最小值,这是减少开销的好方法,因为除非您的数据库与 Web 服务器位于同一物理服务器上,否则所有内容都需要通过网络进行。

确保您执行尽可能少的单独数据调用将减少您花费在提升和删除连接上的时间。

当循环的控制基于(可能相关?)数据集时,您应该始终仔细检查循环中的数据调用,因为这会尖叫加入。

当您尝试使用 SQL 时,尝试熟悉执行计划,这些将帮助您找出为什么运行缓慢的查询查看these resources了解更多信息。

无论你的方法,你决定你需要找出瓶颈在你的代码,一些基本的通过执行可以帮助这一点,因为它可以让你看到自己的问题所在,这也将让你自己识别你的方法可能存在的问题,并建立良好的设计选择习惯。

Marc Gravel 对 C # 数据阅读有一些有趣的观点here这篇文章有点旧,但值得一读。

PIVOTing 您的数据。(对不起 Remus;-))基于您提供的数据示例,以下代码将获得您所需要的,没有查询内递归:

--Test Data
DECLARE @Users AS TABLE ( Id int
                        , Username VARCHAR(50)
                        , Name VARCHAR(50)
                        , Email VARCHAR(50)
                        , [Role] INT --Avoid reserved words for column names.
                        , Active INT --If this is only ever going to be 0 or 1 it should be a bit.
                        );
DECLARE @DataFields AS TABLE ( Id int
                        , Name VARCHAR(50)
                        , [Type] INT --Avoid reserved words for column names.
                        );
DECLARE @DataFieldsValues AS TABLE ( Id int
                        , UserId int
                        , DataFieldId int
                        , Value VARCHAR(50)
                        );
INSERT INTO @users  ( Id
                    , Username
                    , Name
                    , Email
                    , [Role]
                    , Active) 
VALUES (1,'enb081','enb081','enb081@mack.com',2,1),
       (2,'Mack','Mack','mack@mack.com',1,1),
       (3,'Bob','Bobby','bob@mack.com',1,0)
INSERT INTO @DataFields  
                    ( Id
                    , Name
                    , [Type]) 
VALUES (1,'DataField1',3),
       (2,'DataField2',1),
       (3,'DataField3',2),
       (4,'DataField4',0)
INSERT INTO @DataFieldsValues  
                    ( Id
                    , UserId
                    , DataFieldId
                    , Value) 
VALUES (1,1,1,'value11'),
       (2,1,2,'value12'),
       (3,1,3,'value13'),
       (4,1,4,'value14'),
       (5,2,1,'value21'),
       (6,2,2,'value22'),
       (7,2,3,'value23'),
       (8,2,4,'value24')
--Query
SELECT *
FROM
(   SELECT  ut.Username, 
            df.Name as DataFieldName, 
            dfv.Value
    FROM @Users ut
    INNER JOIN @DataFieldsValues dfv 
        ON ut.Id = dfv.UserId
    INNER JOIN @DataFields df 
        ON dfv.DataFieldId = df.Id) src
PIVOT
(   MIN(Value) FOR DataFieldName IN (DataField1, DataField2, DataField3, DataField4)) pvt
--Results
Username    DataField1  DataField2  DataField3  DataField4
enb081      value11     value12     value13     value14
Mack        value21     value22     value23     value24

要记住的最重要的事情是自己尝试一下,因为我们建议的任何东西都可能被您网站上我们不知道的因素所改变。

本站系公益性非盈利分享网址,本文来自用户投稿,不代表边看边学立场,如若转载,请注明出处

(144)
Can负载率:自适应检索CAN通道的sysVar总线负载
上一篇
Centos7打开防火墙:为 Windows服务打开防火墙
下一篇

相关推荐

  • docker游戏服务器:如何使用Docker搭建高性能的游戏服务器

    Docker游戏服务器是一种将游戏服务器部署到容器中的方式,它可以帮助游戏开发者快速、轻松地部署游戏服务器,并且可以更轻松地扩展游戏服务器的容量。…

    2023-04-27 09:55:33
    0 76 38
  • win7玩cf卡顿怎么解决:解决Win7环境下CF游戏卡顿问题

    尝试更新系统:可能是由于系统缺少某些补丁或者更新导致CF卡顿,可以尝试在Windows Update中进行检查更新,并安装最新的补丁和更新。更新显卡驱动:可能是由于显卡驱动过旧或者不兼容导致CF卡顿,可以尝试更新显卡驱动,可以到显卡厂商官网下载最新的驱动进行安装。…

    2023-05-27 11:45:17
    0 90 80
  • cv糖醋排骨是弯的吗弯曲的美味

    cv糖醋排骨不是弯的,它是一种制作方法,通常用来制作排骨。代码:…

    2023-04-01 13:03:36
    0 49 63
  • java ee eclipse使用:如何使用Java EE Eclipse来开发Web应用

    示例示例Java EE Eclipse使用步骤:安装Eclipse IDE。…

    2023-10-12 04:51:32
    0 21 64
  • cookie如何使用:如何使用Cookie来改善用户体验

    Cookie是一种存储在客户端的小型文件,用于记录用户的信息,如访问时间、登录状态等。使用Cookie可以更好地为用户提供服务,比如保存用户的登录状态,记录用户的浏览历史记录等。…

    2023-05-07 02:18:11
    0 97 52
  • cv小敢:如何利用CV小敢提升职业技能?

    cv小敢(Computer Vision Tiny-YOLO)是一种轻量级的物体检测算法,它可以在资源受限的设备上运行,如嵌入式设备、智能手机等。它是基于YOLO(You Only Look Once)算法的一个变体,由Joseph Redmon和Ali Farhadi开发,旨在提高深度学习模型的性能,同时减少模型的大小和计算复杂度。…

    2023-02-09 13:08:59
    0 91 71
  • ubuntu如何编译c语言:在Ubuntu上编译C语言程序的步骤

    示例示例Ubuntu编译C语言的步骤如下:安装gcc编译器:…

    2023-09-08 12:39:20
    0 61 44
  • coremail论客邮箱Coremail论客邮箱

    Coremail论客邮箱是一款专业的企业邮箱服务,可以满足企业对安全、可靠性和高效性的要求。它拥有强大的安全性能,可以提供多种安全保护,包括防止邮件被窃取、拦截恶意邮件、防止跨站脚本攻击等。此外,它还支持多种企业级功能,如组织架构管理、收发邮件管理、文件共享管理、联系人管理等,可以帮助企业提高工作效率,提升企业形象。…

    2023-02-25 04:36:55
    0 97 82

发表评论

登录 后才能评论

评论列表(24条)