简体   繁体   English

非常大的SQL表的注意事项?

[英]Considerations for very large SQL tables?

I'm building, basically, an ad server. 我基本上正在构建一个广告服务器。 This is a personal project that I'm trying to impress my boss with, and I'd love any form of feedback about my design. 这是一个个人项目,我试图给我的老板留下深刻的印象,我喜欢任何形式的关于我的设计的反馈。 I've already implemented most of what I describe below, but it's never too late to refactor :) 我已经实现了下面我描述的大部分内容,但重构永远不会太晚:)

This is a service that delivers banner ads ( http://myserver.com/banner.jpg links to http://myserver.com/clicked ) and provides reporting on subsets of the data. 这是一项提供横幅广告的服务( http://myserver.com/banner.jpg链接到http://myserver.com/clicked ),并提供有关数据子集的报告。

For every ad impression served and every click, I need to record a row that has (id, value) [where value is the cash value of this transaction; 对于每次投放的广告展示和每次点击,我都需要记录一行(ID,值)[其中value是此交易的现金价值; eg -$.001 per served banner ad at $1 CPM, or +$.25 for a click); 例如 - 每1美元CPM每个服务横幅广告$ 0.001,或点击+ 25美元; my output is all based on earnings per impression [abbreviated EPC]: (SUM(value)/COUNT(impressions)) , but on subsets of the data, like "Earnings per impression where browser == 'Firefox'". 我的输出全部基于每次展示的收入[缩写为EPC] :( (SUM(value)/COUNT(impressions)) ,但是在数据的子集上,例如“每次展示的收入,其中浏览器=='Firefox'”。 The goal is to output something like "Your overall EPC is $.50, but where browser == 'Firefox', your EPC is $1.00", so that the end user can quickly see significant factors in their data. 我们的目标是输出类似“您的整体EPC为0.50美元,但浏览器=='Firefox',您的EPC为1.00美元”,以便最终用户可以快速查看其数据中的重要因素。

Because there's a very large number of these subsets (tens of thousands), and reporting output only needs to include the summary data, I'm precomputing the EPC-per-subset with a background cron task, and storing these summary values in the database. 因为这些子集数量非常多(数万个),并且报告输出只需要包含摘要数据,所以我使用后台cron任务预先计算每个子集的EPC,并将这些汇总值存储在数据库中。 Once in every 2-3 hits, a Hit needs to query the Hits table for other recent Hits by a Visitor (eg "find the REFERER of the last Hit"), but usually, each Hit only performs an INSERT, so to keep response times down, I've split the app across 3 servers [bgprocess, mysql, hitserver]. 一旦在每2-3次命中,Hit需要查询Hits表以获取访问者的其他近期命中(例如“查找最后一次命中的REFERER”),但通常,每次Hit只执行一次INSERT,以便保持响应下来,我将应用程序拆分为3个服务器[bgprocess,mysql,hitserver]。

Right now, I've structured all of this as 3 normalized tables: Hits, Events and Visitors. 现在,我将所有这些都构建为3个规范化表:Hits,Events和Visitors。 Visitors are unique per visitor session, a Hit is recorded every time a Visitor loads a banner or makes a click, and Events map the distinct many-to-many relationship from Visitors to Hits (eg an example Event is "Visitor X at Banner Y", which is unique, but may have multiple Hits). 访问者对于每个访问者会话是唯一的,每次访问者加载横幅或点击时都会记录命中,并且事件映射从访问者到命中的不同的多对多关系(例如,事件是“横幅Y处的访客X” “,这是唯一的,但可能有多个Hits)。 The reason I'm keeping all the hit data in the same table is because, while my above example only describes "Banner impressions -> clickthroughs", we're also tracking "clickthroughs -> pixel fires", "pixel fires -> second clickthrough" and "second clickthrough -> sale page pixel". 我将所有匹配数据保存在同一个表中的原因是,虽然我的上述示例仅描述了“横幅展示次数 - >点击次数”,但我们还会跟踪“点击次数 - >像素点火”,“像素点火 - >秒点击“和”第二次点击 - >销售页面像素“。

My problem is that the Hits table is filling up quickly, and slowing down ~linearly with size. 我的问题是Hits表快速填满,并且随着大小线性减慢。 My test data only has a few thousand clicks, but already my background processing is slowing down. 我的测试数据只有几千次点击,但我的后台处理速度已经放慢了。 I can throw more servers at it, but before launching the alpha of this, I want to make sure my logic is sound. 我可以扔更多的服务器,但在启动它的alpha之前,我想确保我的逻辑是合理的。

So I'm asking you SO-gurus, how would you structure this data? 所以我问你SO-gurus,你会如何构建这些数据? Am I crazy to try to precompute all these tables? 我是否疯狂尝试预先计算所有这些表格? Since we rarely need to access Hit records older than one hour, would I benefit to split the Hits table into ProcessedHits (with all historical data) and UnprocessedHits (with ~last hour's data), or does having the Hit.at Date column indexed make this superfluous? 由于我们很少需要访问超过一小时的Hit记录,我是否有利于将Hits表拆分为ProcessedHits(包含所有历史数据)和UnprocessedHits(包含〜last hours的数据),或者将Hit.at Date列索引为make这多余的?

This probably needs some elaboration, sorry if I'm not clear, I've been working for past ~3 weeks straight on it so far :) TIA for all input! 这可能需要一些细化,对不起,如果我不清楚的话,我到目前为止已经连续工作了大约3周:) TIA所有输入!

You should be able to build an app like this in a way that it won't slow down linearly with the number of hits. 您应该能够以这样的方式构建这样的应用程序,使其不会因命中数量而线性减速。

From what you said, it sounds like you have two main potential performance bottlenecks. 根据你的说法,听起来你有两个主要的潜在性能瓶颈。 The first is inserts. 第一个是插入。 If you can have your inserts happen at the end of the table, that will minimize fragmentation and maximize throughput. 如果您可以在表的末尾进行插入,那么可以最大限度地减少碎片并最大化吞吐量。 If they're in the middle of the table, performance will suffer as fragmentation increases. 如果它们处于中间位置,性能将随着碎片的增加而受到影响。

The second area is the aggregations. 第二个区域是聚合。 Whenever you do a significant aggregation, be careful that you don't cause all in-memory buffers to get purged to make room for the incoming data. 无论何时进行重要聚合,请注意不要使所有内存缓冲区被清除以为传入数据腾出空间。 Try to minimize how often the aggregations have to be done, and be smart about how you group and count things, to minimize disk head movement (or maybe consider using SSDs). 尽量减少必须完成聚合的频率,并明智地了解如何对事物进行分组和计数,以最大限度地减少磁头移动(或者考虑使用SSD)。

You might also be able to do some of the accumulations at the web tier based entirely on the incoming data rather than on new queries, perhaps with a fallback of some kind if the server goes down before the collected data is written to the DB. 您也可以完全基于传入数据而不是新查询在Web层上执行某些累积,如果在收集的数据写入数据库之前服务器出现故障,可能会出现某种回退。

Are you using INNODB or MyISAM? 您使用的是INNODB还是MyISAM?

Here are a few performance principles: 以下是一些性能原则:

  1. Minimize round-trips from the web tier to the DB 最大限度地减少从Web层到数据库的往返
  2. Minimize aggregation queries 最小化聚合查询
  3. Minimize on-disk fragmentation and maximize write speeds by inserting at the end of the table when possible 通过在可能的情况下插入表的末尾,最大限度地减少磁盘碎片并最大化写入速度
  4. Optimize hardware configuration 优化硬件配置

Generally you have detailed "accumulator" tables where records are written in realtime. 通常,您有详细的“累加器”表,其中记录是实时写入的。 As you've discovered, they get large quickly. 正如您所发现的那样,它们会迅速变大。 Your backend usually summarizes these raw records into cubes or other "buckets" from which you then write reports. 您的后端通常会将这些原始记录汇总到多维数据集或其他“存储桶”中,然后您可以从中创建报告。 Your cubes will probably define themselves once you map out what you're trying to report and/or bill for. 一旦您确定了您要报告和/或计费的内容,您的多维数据集可能会定义自己。

Don't forget fraud detection if this is a real project. 如果这是一个真实的项目,请不要忘记欺诈检测。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM