2012-07-06 76 views
5

我想知道,在我的情况下,以下哪个示例最适合关闭记录集对象?经典ASP - 何时关闭记录集

1)

这一个闭合环路内的对象,但是当它下一个移动打开一个新的对象。如果有1000条记录,则会打开一个对象1000次并将其关闭1000次。这是我通常会做:

SQL = " ... " 
Set rs1 = conn.Execute(SQL) 
While NOT rs1.EOF 

    SQL = " ... " 
    Set rs2 = conn.Execute(SQL) 
    If NOT rs2.EOF Then 
     Response.Write (...) 
    End If 
    rs2.Close : set rs2 = Nothing 

rs1.MoveNext 
Wend 
rs1.Close : Set rs1 = Nothing 

2)

这个例子是我想知道什么。在循环完成之前是否保存对象闭包(rs2.close),从而获得或降低性能?如果有1000条记录,这将打开1000个对象,但只关闭一次:

SQL = " ... " 
Set rs1 = conn.Execute(SQL) 
While NOT rs1.EOF 

    SQL = " ... " 
    Set rs2 = conn.Execute(SQL) 
    If NOT rs2.EOF Then 
     Response.Write (...) 
    End If 

rs1.MoveNext 
Wend 
rs1.Close : Set rs1 = Nothing 
rs2.Close : set rs2 = Nothing 

我希望我已经解释自己不够好,这不是太愚蠢了。

UPDATE

对于那些谁认为我的查询可以进行修改,以避免N + 1问题(第二查询),那就是:

这是一个在线照片库。我有两张桌子; “photoSearch”和“照片”。第一个“photoSearch”只有几列,包含照片的所有可搜索数据,如“photoID”,“标题”,“标题”,“人物”,“dateCaptured”和“关键字”。它有一个多列全文索引(标题,标题,人物,关键字)。第二个表格“照片”包含所有照片数据;高度,宽度,版权,标题,ID,日期等等。两者都有500K +行,标题和标题字段有时会返回2000+个字符。

这大概是这个查询现在的样子: (需要注意的是:我不能在全文搜索中使用连接,因此关键字存储在一个列中 - 在一个“非标准化”表中。代码为我的应用程序代码在其他地方 - 但它很接近)

SQL = "SELECT photoID FROM photoSearch 
WHERE MATCH (headline, caption, people, keywords) 
AGAINST ('"&booleanSearchStr&"' IN BOOLEAN MODE) 
AND dateCaptured BETWEEN '"&fromDate&"' AND '"&toDate&"' LIMIT 0,50;" 
Set rs1 = conn.Execute(SQL) 
While NOT rs1.EOF 

    SQL = "SELECT photoID, setID, eventID, locationID, headline, caption, instructions, dateCaptured, dateUploaded, status, uploaderID, thumbH, thumbW, previewH, previewW, + more FROM photos LEFT JOIN events AS e USING (eventID) LEFT JOIN location AS l USING (locationID) WHERE photoID = "&rs1.Fields("photoID")&";" 
    Set rs2 = conn.Execute(SQL) 
    If NOT rs2.EOF Then 
     Response.Write (.. photo data ..) 
    End If 
    rs2.Close 

rs1.MoveNext 
Wend 
rs1.Close 

测试时,有它自己的表,“照片搜索”的全文索引,而不是大表,“照片”,似乎改善速度有点。我没有添加“photoSearch”表,它已经存在 - 这不是我的应用程序。如果我尝试加入这两个表以失去第二个查询,那么我会一起丢失索引,导致很长时间 - 所以我无法使用全文连接。这似乎是最快的方法。如果不是全文和加入问题,我已经将这两个查询结合起来了。

回答

4

这是事情。首先,获取你的照片ID并让MySQL认为这是一张只包含照片ID的实际表格,然后让你的实际声明,不需要任何额外的记录集连接...

并且不要忘记从最终做到这一点。下面是示例代码说明:

步骤1创建照片的ID查找表并将其命名为:这将我们PHOTOID查找表,以便将其命名为“PhotoIds”

SELECT photoID FROM photoSearch 
WHERE MATCH (headline, caption, people, keywords) 
AGAINST ('"&booleanSearchStr&"' IN BOOLEAN MODE) 
AND dateCaptured BETWEEN '"&fromDate&"' AND '"&toDate&"' LIMIT 0,50) AS PhotoIds 

步骤2现在我们有照片ID,所以从中获取信息。我们将在WHERE子句之前插入上面的语句,就像我们用真正的表一样。请注意,我们的“假”表格必须位于不合格品之间。

SQL = "SELECT p.photoID, p.setID, p.eventID, p.locationID, p.headline, p.caption, + more FROM 
    photos AS p, 
    events AS e USING (p.eventID), 
    location AS l USING (p.locationID), 
    (SELECT photoID FROM photoSearch WHERE MATCH (headline, caption, people, keywords) 
     AGAINST ('"&booleanSearchStr&"' IN BOOLEAN MODE) AND dateCaptured BETWEEN 
     '"&fromDate&"' AND '"&toDate&"' LIMIT 0,50) AS PhotoIds 
    WHERE p.photoID=PhotoIds.photoID;" 

注:我只是写这些代码在这里,从来没有进行测试。可能有一些拼写错误或smt。请让我知道你是否有麻烦。

现在,让你的首要问题

无需关闭执行的查询,特别是如果你正在使用执行方法。 Execute方法在执行后自动关闭,除非它不返回任何记录集数据(即第一个执行命令的目的),如:“INSERT”,“DELETE”,“UPDATE”。如果你没有打开一个记录集对象,那么为什么要关闭一些永远不会打开的东西呢?相反,您可以使用Set Rs = Nothing来重新引用对象并发送到垃圾回收以释放一些系统资源(这与mysql本身无关)。如果使用“SELECT”查询(将返回一些数据的查询),则必须打开一个记录集对象(ADODB.Recordset),如果打开它,则需要在完成作业后立即关闭它。

最重要的是在每次页面加载后关闭“主连接到mysql服务器”。因此,您可以考虑将连接关闭算法(不关闭记录集)放到包含文件中,并将其插入到与数据库连接的每个页面的末尾。那次长谈短:必须,如果你使用打开()

+0

哇!这个新的查询是有道理的,它的工作。我在MySQL Workbench中测试,它非常快。我需要将它添加到我的应用程序,以查看它是否能够加快速度。我有一个问题;我会在哪里将INNER JOIN放入此查询中?像这个; LEFT JOIN(photoPeople AS pp INNER JOIN people as pe pe.peopleID = pe.PeopleID) ON p.photoID = pp.photoID? – TheCarver 2012-07-08 22:06:52

+0

@PaparazzoKid在使用MySQL时,您不必使用INEER JOIN,LEFT JOIN等。您可以使用“,”(逗号运算符)连接多个表并为这些表伪名。即:(“SELECT t1.name,t2.name FROM very_long_table_name_table1 AS t1,very_long_table_name_table2 AS t2 WHERE t1.id = t2.id”) – htbasaran 2012-07-08 22:54:34

+0

噢,这是一个扳手在作品中。对于MySQL,我一直使用LEFT,RIGHT,JOIN或INNER JOINS - 我需要阅读相关内容。我使用LEFT的原因是我想要加入的表格并不总是有匹配的记录。你的方法会这样吗? – TheCarver 2012-07-08 23:14:16

3

如果您向我们展示您的SQL语句,也许我们可以向您展示如何将它们合并到单个SQL语句中,因此您只需执行一个循环,否则双重循环会严重影响服务器的性能。但在此之前我学会了存储过程和加入,我会做大概是这样的:

Set Conn = Server.CreateObject("Adodb.Connection") 
Conn.Open "ConnectionString" 

Set oRS = Server.CreateObject("Adodb.Recordset") 
oRS.Open "SQL STATEMENT", Conn 

Set oRS2 = Server.CreateObject("Adodb.Recordset") 
oRS2.ActiveConnection = Conn 

Do Until oRS.EOF 

    oRS2.Open "SQL STATEMENT" 
    If oRS2.EOF Then ... 
    oRS2.Close 

oRS.Movenext 
Loop 
oRS.Close 
Set oRS = Nothing 
Set oRS2 = Nothing 
Set Conn = Nothing 
+0

同意100%,该查询(IES)的设计可能可以改善完全避免内部查询使用关闭()。这被称为'选择N + 1问题'http://stackoverflow.com/questions/97197/what-is-the-n1-selects-problem。如果您专注于此问题,而不是优化记录集对象的处理方式,那么您会得到更好的结果。 – 2012-07-07 01:17:45

+0

我知道,我记得这些天..一旦我开始组合SQL查询,服务器的性能显着提高,达到100x。 – 2012-07-07 01:29:44

+0

我实际上使用我的方法获得了更好的结果。尝试和测试。通常,我会尝试将两个查询合并为一个,就像您说的那样,但它似乎不适用于我的情况。我的表格有500k行和许多列,还有一些非常大的列(2000多个字符)。当我的页面只使用一个查询时,它选择该表格中的几乎所有列,然后每页显示50条记录。查询花费了一天!然后,我改变了我的上述方法,只选择顶部查询中的ID,并从循环内的第二个查询中获取大量数据。 – TheCarver 2012-07-07 02:17:50

0

我试图把这个在评论,因为它并不直接回答你原来的问题,但它得到了太久.. :)

您可以尝试使用子查询而不是联接,将外部查询嵌套在第二个查询中。 “...其中photoID在(从photoSearch中选择photoID ...)”。不知道它是否会得到更好的结果,但它可能值得尝试。话虽如此,使用全文搜索确实会改变查询的优化方式,因此可能需要更多的工作来确定合适的索引(需要)。根据您现有的表现,这可能不值得。

您是否确切知道现有的代码/查询是当前的瓶颈?有时候我们花时间来优化我们认为是时可能不会是这样的瓶颈东西... :)

一个额外的想法 - 你可能要考虑一些高速缓存逻辑,以减少冗余的查询量,你可能正在制作 - 无论是在页面级还是在此方法的级别。搜索参数可以连接在一起以形成将数据存储在某种缓存中的密钥。当然,你需要处理适当的缓存失效/失效逻辑。我已经看到系统通过非常简单的缓存逻辑加速到100x这样的瓶颈。

+0

缓存听起来很有趣,可能会进一步研究。我在这个特定的页面或查询中实际上没有任何瓶颈。我纯粹想知道在循环中使用时,关闭记录集对象的最佳方法是什么。循环之后或循环中。 – TheCarver 2012-07-07 14:01:13

+0

好的 - 你确实问过哪个是最好的性能方法,所以我认为人们专注于代码的性能方面是很自然的,在这种情况下,查询比处理记录集对象的影响大得多。作为一般原则,如果你没有性能问题,你可能不应该花时间优化它...... :) – 2012-07-10 18:49:36