草庐IT

mysql - 在 mysql 中查询巨大的数据库表需要太多时间

coder 2023-10-15 原文

我在一个 mysql 数据库表上运行 sql 查询,该表一整天都有 1.1 亿条以上的唯一记录。

问题:每当我使用“where”子句运行任何查询时,它至少需要 30-40 分钟。因为我想在第二天生成大部分数据,所以我需要访问整个数据库表。

能否请您指导我优化/重构部署模型?

网站描述:

mysql  Ver 14.12 Distrib 5.0.24, for pc-linux-gnu (i686) using readline 5.0
4 GB RAM, 
Dual Core dual CPU 3GHz
RHEL 3

my.cnf contents :

[mysqld]
datadir=/data/mysql/data/
socket=/tmp/mysql.sock

sort_buffer_size = 2000000
table_cache = 1024
key_buffer = 128M
myisam_sort_buffer_size = 64M

# Default to using old password format for compatibility with mysql 3.x
# clients (those using the mysqlclient10 compatibility package).
old_passwords=1

[mysql.server]
user=mysql
basedir=/data/mysql/data/

[mysqld_safe]
err-log=/data/mysql/data/mysqld.log
pid-file=/data/mysql/data/mysqld.pid
[root@reports root]#

DB table details:

CREATE TABLE `RAW_LOG_20100504` (
  `DT` date default NULL,
  `GATEWAY` varchar(15) default NULL,
  `USER` bigint(12) default NULL,
  `CACHE` varchar(12) default NULL,
  `TIMESTAMP` varchar(30) default NULL,
  `URL` varchar(60) default NULL,
  `VERSION` varchar(6) default NULL,
  `PROTOCOL` varchar(6) default NULL,
  `WEB_STATUS` int(5) default NULL,
  `BYTES_RETURNED` int(10) default NULL,
  `RTT` int(5) default NULL,
  `UA` varchar(100) default NULL,
  `REQ_SIZE` int(6) default NULL,
  `CONTENT_TYPE` varchar(50) default NULL,
  `CUST_TYPE` int(1) default NULL,
  `DEL_STATUS_DEVICE` int(1) default NULL,
  `IP` varchar(16) default NULL,
  `CP_FLAG` int(1) default NULL,
  `USER_LOCATE` bigint(15) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 MAX_ROWS=200000000;

提前致谢! 问候,

最佳答案

我鼓励您学习如何使用 EXPLAIN分析数据库的查询优化计划。另请参阅 Baron Schwartz 的演讲 EXPLAIN Demystified (他的幻灯片的 PDF 链接在那个页面上)。

了解如何创建索引——这与主键或自动递增伪键不同。查看演示 More Mastering the Art of Indexing作者:松信义典。

您的表可以在 CP_FLAGWEB_STATUS 上使用索引。

CREATE INDEX CW ON RAW_LAW_20100503 (CP_FLAG, WEB_STATUS);

这有助于根据您的 cp_flag 条件查找行的子集。

然后您仍然会遇到 MySQL 的 GROUP BY 查询效率低下的不幸问题。它将临时结果集复制到磁盘上的一个临时文件中,并在那里对其进行排序。磁盘 I/O 往往会降低性能。

您可以提高您的sort_buffer_size 配置参数,直到它足够大,MySQL 可以在内存而不是磁盘上对结果集进行排序。但这可能行不通。

您可能不得不求助于预先计算所需的 COUNT(),并定期更新此统计信息。


@Marcus 的评论给了我另一个想法。您按网络状态分组,网络状态的不同值集是一个相当短的列表,它们不会改变。因此,您可以为每个不同的值运行单独的查询并生成所需的结果,这比使用创建临时表进行排序的 GROUP BY 查询要快得多。或者您可以为每个状态值运行一个子查询,并将它们UNION 在一起:

(SELECT COUNT(*), WEB_STATUS FROM RAW_LOG_20100504 WHERE CP_FLAG > 0 AND WEB_STATUS = 200)
UNION
(SELECT COUNT(*), WEB_STATUS FROM RAW_LOG_20100504 WHERE CP_FLAG > 0 AND WEB_STATUS = 404)
UNION
(SELECT COUNT(*), WEB_STATUS FROM RAW_LOG_20100504 WHERE CP_FLAG > 0 AND WEB_STATUS = 304)
UNION
...etc...
ORDER BY 1 DESC;

因为您的覆盖索引 包括CP_FLAGWEB_STATUS,所以这些查询永远不需要读取表中的实际行。它们只读取索引中的条目,它们可以更快地访问这些条目,因为 (a) 它们位于排序树中,并且 (b) 如果您为 key_buffer_size 分配足够的空间,它们可能会缓存在内存中.

我尝试的EXPLAIN 报告(包含 100 万行测试数据)表明这很好地使用了索引,并且没有创建临时表:

+------+--------------+------------------+------+--------------------------+
| id   | select_type  | table            | key  | Extra                    |
+------+--------------+------------------+------+--------------------------+
|  1   | PRIMARY      | RAW_LOG_20100504 | CW   | Using where; Using index |
|  2   | UNION        | RAW_LOG_20100504 | CW   | Using where; Using index |
|  3   | UNION        | RAW_LOG_20100504 | CW   | Using where; Using index |
| NULL | UNION RESULT | <union1,2,3>     | NULL | Using filesort           |
+------+--------------+------------------+------+--------------------------+

最后一行的 Using filesort 只是意味着它必须在没有索引的情况下进行排序。但是对子查询产生的三行进行排序是微不足道的,MySQL 在内存中完成。


在设计最佳数据库解决方案时,很少有简单的答案。很大程度上取决于您如何使用数据以及哪种查询具有更高的优先级以加快速度。如果有一个适用于所有情况的单一、简单的答案,软件将默认启用该设计,您无需执行任何操作。

您确实需要阅读大量手册、书籍和博客才能了解如何充分利用您可用的所有功能。


是的,我仍然会推荐使用索引。很明显,以前当您查询 1 亿行时没有索引的好处,它是行不通的。

您必须明白,您必须设计有利于您要运行的特定查询的索引。我无法知道您刚刚在评论中描述的索引是否合适,因为您没有显示您正在尝试加速的其他查询。

索引是一个复杂的话题。如果您在错误的列上定义了索引,或者如果您以错误的顺序获取列,则给定查询可能无法使用它。自 1994 年以来,我一直在支持 SQL 开发人员,但我从未找到一条简明的规则来解释如何设计索引。

您似乎需要一位导师,因为您正处于需要回答很多问题的阶段。在您工作的地方是否有人可以寻求帮助?

关于mysql - 在 mysql 中查询巨大的数据库表需要太多时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2769046/

有关mysql - 在 mysql 中查询巨大的数据库表需要太多时间的更多相关文章

  1. ruby - 我需要将 Bundler 本身添加到 Gemfile 中吗? - 2

    当我使用Bundler时,是否需要在我的Gemfile中将其列为依赖项?毕竟,我的代码中有些地方需要它。例如,当我进行Bundler设置时:require"bundler/setup" 最佳答案 没有。您可以尝试,但首先您必须用鞋带将自己抬离地面。 关于ruby-我需要将Bundler本身添加到Gemfile中吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/4758609/

  2. ruby - ECONNRESET (Whois::ConnectionError) - 尝试在 Ruby 中查询 Whois 时出错 - 2

    我正在用Ruby编写一个简单的程序来检查域列表是否被占用。基本上它循环遍历列表,并使用以下函数进行检查。require'rubygems'require'whois'defcheck_domain(domain)c=Whois::Client.newc.query("google.com").available?end程序不断出错(即使我在google.com中进行硬编码),并打印以下消息。鉴于该程序非常简单,我已经没有什么想法了-有什么建议吗?/Library/Ruby/Gems/1.8/gems/whois-2.0.2/lib/whois/server/adapters/base.

  3. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  4. ruby - rspec 需要 .rspec 文件中的 spec_helper - 2

    我注意到像bundler这样的项目在每个specfile中执行requirespec_helper我还注意到rspec使用选项--require,它允许您在引导rspec时要求一个文件。您还可以将其添加到.rspec文件中,因此只要您运行不带参数的rspec就会添加它。使用上述方法有什么缺点可以解释为什么像bundler这样的项目选择在每个规范文件中都需要spec_helper吗? 最佳答案 我不在Bundler上工作,所以我不能直接谈论他们的做法。并非所有项目都checkin.rspec文件。原因是这个文件,通常按照当前的惯例,只

  5. ruby - 如何在 Lion 上安装 Xcode 4.6,需要用 RVM 升级 ruby - 2

    我实际上是在尝试使用RVM在我的OSX10.7.5上更新ruby,并在输入以下命令后:rvminstallruby我得到了以下回复:Searchingforbinaryrubies,thismighttakesometime.Checkingrequirementsforosx.Installingrequirementsforosx.Updatingsystem.......Errorrunning'requirements_osx_brew_update_systemruby-2.0.0-p247',pleaseread/Users/username/.rvm/log/138121

  6. ruby-on-rails - 在 Rails 和 ActiveRecord 中查询时忽略某些字段 - 2

    我知道我可以指定某些字段来使用pluck查询数据库。ids=Item.where('due_at但是我想知道,是否有一种方法可以指定我想避免从数据库查询的某些字段。某种反拔?posts=Post.where(published:true).do_not_lookup(:enormous_field) 最佳答案 Model#attribute_names应该返回列/属性数组。您可以排除其中一些并传递给pluck或select方法。像这样:posts=Post.where(published:true).select(Post.attr

  7. ruby-on-rails - Ruby 检查日期时间是否为 iso8601 并保存 - 2

    我需要检查DateTime是否采用有效的ISO8601格式。喜欢:#iso8601?我检查了ruby​​是否有特定方法,但没有找到。目前我正在使用date.iso8601==date来检查这个。有什么好的方法吗?编辑解释我的环境,并改变问题的范围。因此,我的项目将使用jsapiFullCalendar,这就是我需要iso8601字符串格式的原因。我想知道更好或正确的方法是什么,以正确的格式将日期保存在数据库中,或者让ActiveRecord完成它们的工作并在我需要时间信息时对其进行操作。 最佳答案 我不太明白你的问题。我假设您想检查

  8. ruby - Ruby 有 `Pair` 数据类型吗? - 2

    有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳

  9. ruby-on-rails - 将 Ruby 中的日期/时间格式化为 YYYY-MM-DD HH :MM:SS - 2

    这个问题在这里已经有了答案:Railsformattingdate(4个答案)关闭4年前。我想格式化Time.Now函数以显示YYYY-MM-DDHH:MM:SS而不是:“2018-03-0909:47:19+0000”该函数需要放在时间中.现在功能。require‘roo’require‘roo-xls’require‘byebug’file_name=ARGV.first||“Template.xlsx”excel_file=Roo::Spreadsheet.open(“./#{file_name}“,extension::xlsx)xml=Nokogiri::XML::Build

  10. ruby - 查找字符串中的内容类型(数字、日期、时间、字符串等) - 2

    我正在尝试解析一个CSV文件并使用SQL命令自动为其创建一个表。CSV中的第一行给出了列标题。但我需要推断每个列的类型。Ruby中是否有任何函数可以找到每个字段中内容的类型。例如,CSV行:"12012","Test","1233.22","12:21:22","10/10/2009"应该产生像这样的类型['integer','string','float','time','date']谢谢! 最佳答案 require'time'defto_something(str)if(num=Integer(str)rescueFloat(s

随机推荐