我正在为我的 oracle 数据库在 JSP 中创建一个 API。
我有两个表,每个表包含 20k 条记录。我需要执行自然连接,结果将以 JSON 格式显示在 JSP 页面中。我的问题是加载 JSON 页面需要将近 3 分钟。
请告诉我如何提高页面的性能?
我正在为我的 oracle 数据库在 JSP 中创建一个 API。
我有两个表,每个表包含 20k 条记录。我需要执行自然连接,结果将以 JSON 格式显示在 JSP 页面中。我的问题是加载 JSON 页面需要将近 3 分钟。
请告诉我如何提高页面的性能?
要优化流程(任何流程!),您需要了解它在哪里花费时间。如果您在数据库中花费 10 秒,在 java 中花费 170 秒,那么您显然不想从优化查询开始。
您应该做的第一件事是直接在数据库中运行查询,使用最少的图形显示,例如在 SQL*Plus 中:
set timing on
set autotrace traceonly statistics
这将使您大致了解从数据库中获取所花费的时间。最有可能连接两个 20k 行的小表,这不应该超过 1 秒。
在数据库服务器上运行查询以消除任何网络延迟。
如果需要更多时间,则意味着行非常大(许多大列),或者您的高水位线异常大。
我假设 Oracle 正在为查询选择正确的计划(这应该是FULL SCAN + HASH JOIN
因为您没有使用 WHERE 条件)。
首先,您应该知道有些顾问通过调整其他人的笨拙代码过着很好的生活。如果性能优化只是几个规则的问题,他们就无法做到这一点。你案件的具体细节真的很重要。
所以这里有一些观察。
我们有两个感兴趣的陈述。在问题正文中:
“我的问题是加载 JSON 页面需要将近 3 分钟。”
...并在评论中:
“在 oracle 中平均需要超过 50 秒”
这表明大部分时间都没有花在数据库中。因此,调优的首要重点应该是前端代码或网络。20,000 行的结果集(包括来自两个表的记录)可能是很多数据包。也许您的网络/系统管理员可以提供建议。
要检查的一件事是您正在从数据库中收集信息集,而不是逐行(或者更糟糕的是,逐个属性)。
即便如此,在数据库中获取两万行数据需要 50 秒的时间,除非这些行真的很长。或者没有足够的内存来对哈希连接进行排序,所以它正在分页到磁盘。
“ 50 秒是合理的时间吗?”
定义合理。如果我是用户并且我有一个客户在打电话,并且在此查询返回之前我无法回复他们,那么这当然是完全不可接受的。但是,如果这是一个异步 Web 服务,它在完成时将消息放入队列,并且我可以在下一小时的任何时间处理它,那么 50 秒就可以了。
正如我已经说过的,您案件的具体细节很重要。但是你没有提供任何细节,所以你可以拥有的只是一般性。总的来说,我会说几乎一分钟的时间太长而无法加入并选择一个?二?二十?两张微不足道的小桌子上的任何行。
但让我重复一遍:50 秒还不到您所说的填充页面所需总时间的一半。如果你传回几行而不是两万行,那么其他 130 秒会变得更加明显。
WHERE 子句中条件的可用索引
建议确保 WHERE 子句中条件的最佳索引可用。有关如何检查搜索条件和创建适当索引的更多详细信息,请参阅主题“加速搜索和过滤器”。例如,如果您想获得更好的查询性能:
SELECT * FROM customer WHERE City='Kapaa Kauai' AND State='HI'
加快速度的最佳方法是创建以下区分大小写的索引:
ABSTable1.AddIndex('idxCityState', 'City;State', []);
如果您需要为查询获得更好的性能:
SELECT * FROM customer WHERE Upper(City)='KAPAA KAUAI'
加快速度的最佳方法是创建以下不区分大小写的索引:
ABSTable1.AddIndex('idxCity_nocase', 'City', [ixCaseInsensitive]);
JOIN 条件的可用索引
要改进 JOIN 查询,请检查 JOIN 条件中的每个字段是否都有索引。例如,如果您想提高查询的性能:
SELECT Event_Name,Venue FROM Events e JOIN Venues v ON (e.VenueNo = v.VenueNo)
您可以创建以下索引:
VenuesTable.AddIndex('idxVenueNo', 'VenueNo', [ixPrimary]);
EventsTable.AddIndex('idxVenueNo', 'VenueNo', []);
将带有 OR 条件的查询重写为 UNION
Absolute DB 不能使用索引来提高带有 OR 条件的查询的性能。您可以加快查询速度
SELECT * FROM table WHERE (Field1 = 'Value1') OR (Field2 = 'Value2')
通过在上述条件下为每个字段创建索引并使用 UNION 运算符而不是使用 OR:
SELECT ... WHERE Field1 = 'Value1'
UNION
SELECT ... WHERE Field2 = 'Value2'
ORDER BY 子句的可用索引
如果您想使用 ORDER BY 子句从单个表中加速“实时”SELECT,您可以为 ORDER BY 字段创建复合索引。例如,如果您想提高查询速度:
SELECT * FROM Employee ORDER BY LastName, FirstName
您可以通过创建以下复合索引来做到这一点:
ABSTable1.AddIndex('idxLastNameFirstName', 'LastName;FirstName', []);
GROUP BY 子句的可用索引
要使用 GROUP BY 子句从单个表中获得更好的 SELECT 性能,可以为 GROUP BY 字段创建复合索引。例如,如果您想加快查询速度:
SELECT * FROM Employee GROUP BY FirstName
您可以创建以下索引:
ABSTable1.AddIndex('idxFirstName', 'FirstName', []);
从内存表中选择
如果您将所有数据从磁盘表移动到内存表,并且您将使用磁盘表的内存副本执行查询(在查询执行前将 TABSQuery.InMemory 属性设置为 True),您的查询性能也会提高。
选择进入与插入选择
在某些情况下 SELECT ... INTO some_table 查询比 INSERT INTO some_table (SELECT ...) 运行得更快,在另一些情况下 INSERT INTO 更快。请注意,RequestLive 属性可能会对这些查询的性能产生影响。