5

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

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

我希望我已经很好地解释了自己,而且这不是太愚蠢。

更新

对于那些认为可以修改我的查询以避免 N+1 问题(第二次查询)的人,这里是:

这是一个在线照片库。我有两张桌子;“照片搜索”和“照片”。第一个,“photoSearch”,只有几列,包含照片的所有可搜索数据,例如“photoID”、“headline”、“caption”、“people”、“dateCaptured”和“keywords”。它有一个多栏全文索引(标题、标题、人物、关键字)。第二个表“照片”包含所有照片数据;高度、宽度、版权、标题、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”上拥有全文索引,而不是在大表“photos”上,似乎在一定程度上提高了速度。我没有添加“photoSearch”表,它已经存在 - 这不是我的应用程序。如果我尝试加入两个表以丢失第二个查询,我会一起丢失我的索引,从而导致很长时间 - 所以我不能使用全文连接。这似乎是最快的方法。如果不是因为全文和连接问题,我早就将这两个查询结合起来了。

4

3 回答 3

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 服务器的主连接”。因此,您可以考虑将连接关闭算法(不是记录集关闭)放入包含文件中,并将其插入到与数据库建立连接的每一页的末尾。长话短说:如果使用Open( ),则必须使用Close( )

于 2012-07-08T06:45:45.843 回答
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
于 2012-07-07T00:55:27.673 回答
0

我试着把它放在评论中,因为它没有直接回答你原来的问题,但它太长了.. :)

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

你确定这个现有的代码/查询是当前的瓶颈吗?有时我们会花时间优化我们认为是瓶颈的东西,而事实并非如此...... :)

另一个想法 - 您可能需要考虑一些缓存逻辑来减少您可能进行的冗余查询的数量 - 无论是在页面级别还是在此方法级别。搜索参数可以连接在一起以形成用于将数据存储在某种缓存中的键。当然,您需要处理适当的缓存失效/到期逻辑。我已经看到系统速度提高了 100 倍,非常简单的缓存逻辑添加到这样的瓶颈中。

于 2012-07-07T05:29:50.377 回答