假设名为'log'的表,其中有大量记录。适用于SQL中日志记录表的查询和索引
的应用程序通常通过简单的SQL检索数据:
SELECT *
FROM log
WHERE logLevel=2 AND (creationData BETWEEN ? AND ?)
logLevel
和creationData
有指标,但记录的数量使得它需要更长的时间来检索数据。
我们如何解决这个问题?
假设名为'log'的表,其中有大量记录。适用于SQL中日志记录表的查询和索引
的应用程序通常通过简单的SQL检索数据:
SELECT *
FROM log
WHERE logLevel=2 AND (creationData BETWEEN ? AND ?)
logLevel
和creationData
有指标,但记录的数量使得它需要更长的时间来检索数据。
我们如何解决这个问题?
看看你的执行计划/“EXPLAIN PLAN”结果 - 如果你正在检索大量数据,那么你可以做很少的事情来提高性能 - 你可以尝试改变你的SELECT
声明,只包括你的列但是它不会改变你正在做的逻辑读取的次数,所以我怀疑它只会对性能产生不可忽略的影响。
如果您只是检索少量的记录,那么LogLevel的索引和CreationDate上的索引应该有效。
更新: SQL服务器主要用于查询海量数据库的小型子集(例如,将单个客户记录从数据库返回数百万个数据库)。它并没有真正为回归真正的大数据集做好准备。如果你正在返回的数据量是真的大,那么只有一定的数量,你将能够做,所以我不得不问:
什么是你实际上是试图达到?
如果要显示日志消息给用户,那么他们只打算有兴趣在时间的一小部分,所以你可能也想看看分页SQL数据的有效方法 - 如果你一次只能回复500条左右的记录,但它应该仍然很快。
如果您正在尝试进行某种统计分析,那么您可能需要将数据复制到更适合统计分析的数据存储中。 (不知道是什么,但是,这不是我的专业领域)
+1问这个问题背后的问题是什么”你究竟在努力实现什么“ – 2010-08-16 16:00:42
1:不要使用Select *
2:确保你的指标是正确的,你的统计信息是最新的
3 :(可选)如果您发现您没有查看日志数据超过特定时间(以我的经验,如果发生超过一周以前,我可能不会需要它的日志)建立一个工作,将其归档到某些备份中,然后删除未使用的记录。这将减小表格大小,减少搜索表格所花费的时间。
您是否需要所有列?第一步应该只选择你实际需要检索的那些。
另一方面是数据到达您的应用程序(填充数据集/按顺序读取/?)后对数据执行的操作。
在处理应用程序方面可能有一些改进的潜力。
你应该回答自己这些问题:
你需要在一次保存所有在内存中返回的数据?您在检索方每行分配多少内存?你一次需要多少内存?你可以重用一些内存吗?
根据您使用的是哪种SQL数据库,您可能会查看Horizaontal Partitioning。通常情况下,这可以完全在数据库的一面完成,因此您不需要更改代码。
'shard'可以很好! – 2010-08-17 06:53:28
对我来说,有两件事情可以做,
分区表水平基础上的日期列
使用预聚合的基本概念。
预聚合: 在preagg你将有一个 “记录” 表, “logs_temp” 表中, “logs_summary” 表和 “logs_archive” 表。日志和logs_temp表的结构是相同的。应用程序的流程就是这样,所有日志都记录在日志表中,然后每个小时执行一个cron作业,执行以下操作:
a。将日志表中的数据复制到“logs_temp”表中并清空日志表。这可以使用阴影表技巧完成。
b。 c。从logs_temp表中汇总该特定小时的日志。将汇总结果保存在汇总表中
d。将记录从logs_temp表复制到logs_archive表,然后清空logs_temp表。
这种方式的结果是在汇总表中预先汇总的。
无论何时您希望选择结果,都可以从汇总表中选择它。
这样的选择速度非常快,因为记录的数量远远少于数据每小时预先聚合的数量。你甚至可以将门槛从一小时增加到一天。这一切都取决于你的需求。
现在插入也会很快,因为日志表中的数据量并不多,因为它仅保留最后一个小时的数据,因此插入时的索引重新生成花费的时间与非常大数据集,从而使插入更快。
您可以阅读更多有关影子表招here
我采用的预聚合方法建立在WordPress的新闻网站。我不得不为新闻网站开发一个插件,它会显示最近流行的(最近3天流行的)新闻项目,并且每天有100K次点击,而这个预先聚集的事情对我们有很大的帮助。查询时间从2秒以上下降到不到1秒。我打算尽快将该插件公开发布。
根据其他答案,除非你真的需要所有的字段,否则不要使用'select *'。
日志级别和creationData有指标
你需要与这两个值一个指标,你把他们什么样的顺序会影响性能,但是假设你有一个小的数目可能记录等级值(和数据不会倾斜),您将获得更好的性能,首先将creationData。
请注意,最佳索引将降低查询记录(N)的成本,即记录数量增加时它仍会变慢。
C.
我真的希望通过creationData
你的意思是creationDate
。
首先,仅有指数在logLevel
和creationData
是不够的。如果你有2个单独的索引,Oracle将只能使用1 你需要的是一个单一指数在这两个领域:
CREATE INDEX i_log_1 ON log (creationData, logLevel);
注意,我把creationData第一。这样,如果只将该字段放在WHERE子句中,它仍然可以使用索引。 (就日期过滤似乎更可能的情况是在日志级别)。
然后,确保表中填充了数据(您将在生产中使用尽可能多的数据)并刷新表上的统计数据。
如果表是大(至少几十万行),使用下面的代码以刷新统计:
DECLARE
l_ownname VARCHAR2(255) := 'owner'; -- Owner (schema) of table to analyze
l_tabname VARCHAR2(255) := 'log'; -- Table to analyze
l_estimate_percent NUMBER(3) := 5; -- Percentage of rows to estimate (NULL means compute)
BEGIN
dbms_stats.gather_table_stats (
ownname => l_ownname ,
tabname => l_tabname,
estimate_percent => l_estimate_percent,
method_opt => 'FOR ALL INDEXED COLUMNS',
cascade => TRUE
);
END;
否则,如果表很小,使用
ANALYZE TABLE log COMPUTE STATISTICS FOR ALL INDEXED COLUMNS;
另外,如果表格变大,你应该考虑按照creationDate列的范围对它进行分区。看到这些链接的详细信息:
什么是 '解释计划' 告诉你关于你的查询? – 2010-08-16 14:41:14