全局对象与多个新对象?

发布于 2024-12-05 06:20:50 字数 1403 浏览 2 评论 0原文

假设我有一个方法,需要在每次运行期间创建少量对象,并且该方法将被多次调用,即从数据库中删除给定行的方法。每次创建一个新对象并调用垃圾收集器(或类似的)以在最后销毁它,或者每次重新初始化该值会更好吗?

示例:
每次使用新的构造函数:

private void RemoveFolder(string dir)
{
    OleDbCommand cmd2 = connection.CreateCommand();
    OleDbParameter parameterC = new OleDbParameter();
    cmd2.Parameters.Add(parameterC);
    parameterC.Value = dir;

    cmd2.CommandText = "DELETE * FROM [Directories] WHERE Path = ?";
    cmd2.ExecuteNonQuery();
    cmd2.Dispose();
}

使用单个全局变量(在构造函数内初始化):

private void RemoveFolder(string dir)
{
    parameterC.Value = dir;

    cmd2.CommandText = "DELETE * FROM [Directories] WHERE Path = ?";
    cmd2.ExecuteNonQuery();
}

编辑:当我说更好时,我的意思是在正常的非“关键任务”期间“作为一个整体”性能的大幅提升将胜过稳定性的小幅下降。

EDIT2

多次调用类似方法的示例

(请注意,这是我的另一个方法,AddFolder)

foreach (DirectoryInfo directory in directories)
{
    parameter.Value = directory.FullName;
    cmd.CommandText = "SELECT LastModified FROM Directories WHERE Path = ?";
    reader = cmd.ExecuteReader();

    while (reader.Read())
    {
        output += reader.GetString(0);
    }

    if (output == null)
    {
        Console.WriteLine("New Directory! " + directory.FullName);
        AddFolder(directory);
    }
    output = null;
    reader.Close();
 }

Say I was to have a method that required a small number of objects to be created during each run, and the method would be called multiple times, i.e. a method to delete a given row from a database. Would it be better to create a new object each time and call the Garbage Collector (or similar) to destroy it at the end, or reinitialise the value each time?

Example:
Using new constructors each time:

private void RemoveFolder(string dir)
{
    OleDbCommand cmd2 = connection.CreateCommand();
    OleDbParameter parameterC = new OleDbParameter();
    cmd2.Parameters.Add(parameterC);
    parameterC.Value = dir;

    cmd2.CommandText = "DELETE * FROM [Directories] WHERE Path = ?";
    cmd2.ExecuteNonQuery();
    cmd2.Dispose();
}

Using a singular global variable (initialised within the constructor):

private void RemoveFolder(string dir)
{
    parameterC.Value = dir;

    cmd2.CommandText = "DELETE * FROM [Directories] WHERE Path = ?";
    cmd2.ExecuteNonQuery();
}

EDIT: When I say better, I mean "as-a-whole" during normal non-"mission-critical" programs, where a large increase in performance would trump a minor decrease in stability.

EDIT2

An example of calling a similar method multiple times

(Note that this is for another method of mine, AddFolder)

foreach (DirectoryInfo directory in directories)
{
    parameter.Value = directory.FullName;
    cmd.CommandText = "SELECT LastModified FROM Directories WHERE Path = ?";
    reader = cmd.ExecuteReader();

    while (reader.Read())
    {
        output += reader.GetString(0);
    }

    if (output == null)
    {
        Console.WriteLine("New Directory! " + directory.FullName);
        AddFolder(directory);
    }
    output = null;
    reader.Close();
 }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

又怨 2024-12-12 06:20:50

您的问题是我需要优化该代码吗?

我的总体看法是,

  1. 如果优化它很容易,并且代码仍然保持简单,那么就比这样做更容易,
    否则,如果不确定它是否会产生影响,就不要这样,
  2. 如果不确定,请测量它,
  3. 在相关代码附近留下评论

如何测量?
您可以查看您的程序是否运行缓慢,或者是否使用了太多内存。

Your question is Do I need to optimize that code?

My opinion in general,

  1. If it two easy to optimized it, and code still remain simple than do it,
    Otherwise if don't sure if it will give an impact than leave it that way,
  2. Measure it if you don't sure
  3. Leave comment near to the involved code

How to measure it?
You can see if your program is running to slow, or if it using to much memory..

笑红尘 2024-12-12 06:20:50

关于您的第二次编辑,

您可以将 foreach 循环转换为 LINQ,
聚合所有目录,然后立即聚合
将目录添加到您的数据库中

您的代码看起来会更优雅,并且它将解决您的主要问题

请参阅http:// www.linqtutorial.net/linqExamples.html 有一段如何用 LINQ 替换迭代循环

Regarding to your second edit,

You can convert the foreach loop to LINQ,
Aggregate all of the directories, and then at once
Add the directories to you DB

Your code will look more elegant, and it will solve your main question

See http://www.linqtutorial.net/linqExamples.html there is paragraph how to replace iterative loop with LINQ

如若梦似彩虹 2024-12-12 06:20:50

这里您主要关心的性能问题是您为查询的“准备”付出了多少费用。准备是解析查询和(更重要的是)确定查询计划的地方。确定查询计划的成本可能相当高,并且您希望最大限度地减少执行此操作的次数

(注意:即使示例中的 DELETE ... WHERE ... 也需要查询计划。)

某些 DBMS 和 ADO.NET 提供程序在“重用”方面比其他提供程序更好查询计划。例如,在 Oracle/ODP.NET 上,重复重新创建 DbCommand 可能并不重要 - Oracle 倾向于“看到”这是之前使用过的相同查询,并重用该查询查询计划。

另一方面,如果您想确保查询准备一次并重复使用多次,无论您使用什么 DBMS,保持相同的 DbCommand 整个应用程序执行过程中的对象(甚至显式调用 DbCommand.Prepare),如下所示:

var conn = new OracleConnection("your connection string"); // Or DB2Connection, SqlConnection or NpgsqlConnection or whatever...
conn.Open();

// Execute once:
var cmd = conn.CreateCommand();
cmd.CommandText = "DELETE FROM YOUR_TABLE WHERE YOUR_FIELD = :your_param";
var param = cmd.CreateParameter();
param.ParameterName = "your_param";
param.DbType = ...;
cmd.Parameters.Add(param);
cmd.Prepare(); // Not really important for Oracle, but may be important for others.

// Execute multiple times:
param.Value = "some value";
int row_count = cmd.ExecuteNonQuery();

// If you are concerned with long-lived connections, you'll typically be able to do this:
conn.Close();
// ...
conn.Open();
param.Value = "some other value";
row_count = cmd.ExecuteNonQuery();

// Etc..

因此:

  • 如果您的程序仅适用于单个 DBMS/ADO.NET 提供程序,并且您知道它将重用查询有效地计划,你一点也不介意更昂贵的 C# 代码,您可能会选择“重复娱乐”解决方案。它还可能允许稍微短一些的 C# 代码。
  • 然而,我更喜欢“创建一次,多次重用”的解决方案 - 无论我使用什么 DBMS,我都会获得最佳性能。即使在那些足够智能、可以重用查询计划的 DBMS 下,我仍然可以避免重新执行 C# 代码和相关的垃圾收集压力。

The major performance concern you have here is how much you pay for the "preparation" of the query. Preparation is where query gets parsed and (more importantly) query plan determined. The determination of query plan can be rather expensive and you want to minimize how many times this has to be done.

(NOTE: Even DELETE ... WHERE ... from your example needs a query plan.)

Some DBMSes and ADO.NET providers are better than others in "reusing" query plans. On Oracle/ODP.NET, for example, it probably doesn't matter if you repeatedly recreate your DbCommand - Oracle will tend to "see" that this is the same query that was used before and reuse the query plan.

On the other hand, if you want to ensure query is prepared once and reused multiple times, no matter what DBMS you use, it is not a bad idea to keep the same DbCommand object throughout your application execution (and even explicitly call DbCommand.Prepare), something like this:

var conn = new OracleConnection("your connection string"); // Or DB2Connection, SqlConnection or NpgsqlConnection or whatever...
conn.Open();

// Execute once:
var cmd = conn.CreateCommand();
cmd.CommandText = "DELETE FROM YOUR_TABLE WHERE YOUR_FIELD = :your_param";
var param = cmd.CreateParameter();
param.ParameterName = "your_param";
param.DbType = ...;
cmd.Parameters.Add(param);
cmd.Prepare(); // Not really important for Oracle, but may be important for others.

// Execute multiple times:
param.Value = "some value";
int row_count = cmd.ExecuteNonQuery();

// If you are concerned with long-lived connections, you'll typically be able to do this:
conn.Close();
// ...
conn.Open();
param.Value = "some other value";
row_count = cmd.ExecuteNonQuery();

// Etc..

So:

  • If your program only works on a single DBMS/ADO.NET provider and you know it will reuse query plans efficiently and you don't mind slightly more expensive C# code, you may go for the "repeated recreation" solution. It may also allow for a slightly shorter C# code.
  • However, I prefer "create once, reuse many times" solution - I'll get optimal performance whatever DBMS I use. And even under those DBMSes intelligent enough to reuse query plans, I'll still avoid re-execution of the C# code and associated garbage collection pressure.
活雷疯 2024-12-12 06:20:50

我认为这里的关键建议是不要留下挥之不去的数据库连接,然后临时打开和操作。我注意到你的问题实际上围绕着是否重用命令 - 当你观察时,注意到你的连接必须已经是可重用的......我不推荐这样做,并建议你将每个数据库操作视为一个原子单元工作,包括连接利用率等。

I think the key piece of advice here is not to leave lingering database connections around, and then open and operate on an ad hoc basis. I notice that your question really revolves around whether to reuse a command or not - when, on looking, noticing your connection must already be reusable... I wouldn't recommend this and would suggest you think of each database operation as an atomic unit of work, including connection utilisation and all.

美胚控场 2024-12-12 06:20:50

最好使用第一种方法,这样执行查询的逻辑就留在单个函数中。

It is better to use the first method, so that the logic of executing the query stays in a single function.

请止步禁区 2024-12-12 06:20:50

我认为正确的版本介于两者之间

public foo() 
{
   var context = generateContext(dir);
   context.excute();
}

只需将两个目标分开

  1. 创建上下文
  2. 执行它

在创建上下文中使用可以使用单例

I think the correct version is in between

public foo() 
{
   var context = generateContext(dir);
   context.excute();
}

Just split the two goals

  1. Creating the context
  2. Execute it

In the creating context use can use singleton

你的呼吸 2024-12-12 06:20:50

我更喜欢使用全局变量,而不是每次操作都重新创建相同的对象。
一次性分配成本很小,而每次迭代创建对象的成本可能很高。

I would prefer using global variables and not recreating the same objects each operation.
The one time allocation cost is minor, whereas creating the objects every iteration can be costly.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文