我需要一些选择。
我有一张表格如下,约有78,000,000行...
以下是我的查询示例。
SELECT lookup, date, time, count(lookup) as count FROM dnstable
WHERE STR_TO_DATE(`date`, '%d-%b-%Y') >= '$date1' AND STR_TO_DATE(`date`, '%d-%b-%Y') <= '$date2' AND
time >= '$hour1%' AND time <= '$hour2%' AND
`loc` LIKE '%$prov%' AND
lookup REGEXP 'ca|com|org|net' AND
lookup NOT LIKE '%.arpa' AND
lookup NOT LIKE '%domain.ca' AND
ip NOT LIKE '192.168.2.1' AND
ip NOT LIKE '192.168.2.2' AND
ip NOT LIKE '192.168.2.3'
GROUP BY lookup
ORDER BY count DESC
LIMIT 100
我的mysql服务器配置像我发现的几个高用例。硬件很好,有4个核心,8个公羊。
此查询大约需要180秒......有没有人有一些提示让这更有效?
答案 0 :(得分:3)
这里有很多错误。很多东西。我会查看查询选项的其他答案(你使用了很多LIKES,NOT LIKES和函数....你在unkeyed列上做它们......)。如果我在你的情况下,我会重新设计我的整个数据库。您好像使用它来存储DNS条目 - 主机名到IP地址。
您可能无法重新设计数据库 - 可能是客户数据库或您无法控制的内容。也许他们有很多依赖于当前数据库设计的应用程序。但是,如果您可以重构数据库,我强烈建议您这样做。
以下是我要做的事情的基本概要:
将TLD(顶级域)存储在单独的列中作为ENUM。使它成为一个索引,因此它很容易搜索,而不是试图使用正则表达式.com,.arpa等。无论如何TLD都是有限的,并且它们不会经常更改,所以这是ENUM的一个很好的候选者。
将没有TLD的域存储在常规列和反向列中。您可以索引两列,但根据您的搜索,您可能只需要索引反向列。基本上,使用反向列可以搜索一个域中的所有主机(例如google),而无需每次都进行全文搜索。 MySQL可以在反向列中对字符串“elgoog”进行密钥搜索。由于DNS是一个层次结构,因此非常适合。
分别将日期和时间列从VARCHAR更改为DATE和TIME。这是一个明显的变化。没有更多的str_to_time,str_to_date等。绝对没有必要这样做。
以不同方式存储IP地址。没有理由在这里使用VARCHAR - 它效率低,没有意义。相反,为每个八位字节使用四个单独的列(这是安全的,因为所有IPv4地址都有四个八位字节,不多也不少)作为无符号TINYINT值。这将给你0-255,你需要的范围。 (无论如何,每个IP八位字节实际上都是8位。)这应该使搜索速度更快,特别是如果你键入列。
ex:select * from table where octet1!= 10; (这将过滤掉所有10.0.0.0/8私有IP空间)
这里的基本问题是您的数据库设计存在缺陷 - 您的查询使用的是未编入索引的列,并且您的查询效率低下。
如果你坚持使用当前的设计......我不确定我是否能真正帮助你。对不起。
答案 1 :(得分:2)
我敢打赌,这里真正的大问题是STR_TO_DATE函数。 如果可能,请尝试使用日期列来真正拥有DATE数据类型。 (DATE,DATETIME,TIMESTAMP)
将这个新的或更改的列(带有日期数据类型)编入索引会加快对该列的选择。您必须避免日期解析当前缺少列'date'的错误数据类型。这种解析/转换避免了MySQL在'date'列上使用索引。
结论:使'date'列具有Date数据类型,将此列编入索引,并且不要在语句中使用STR_TO_DATE。
我暗示这些本地IP地址在使用否定时不是很有选择性,对吧? (这取决于表中的典型数据。) 由于未对ip-column编制索引,因此对该列的选择始终会导致全表扫描。当对ip的不等(&lt;&gt;)选择非常有选择性时,则考虑在其上放置索引并将语句改为不使用'like'但是&lt;&gt;代替。但我不认为对ip的不平等选择是非常有选择性的。
结论:我认为你不能在这里取得任何重大成就。
答案 2 :(得分:0)
一些提示
NOT LIKE
REGEXP
STR_TO_DATE(date, '%d-%b-%Y') >= '$date1'
尝试将MySQL格式的日期传递给查询,而不是使用STR_TO_DATE
lookup
编入索引。尝试缓存查询结果(如果可能, )。
答案 3 :(得分:0)
问题是LIKE
意味着全表遍历!这就是你看到这个的原因。
我建议的第一件事就是摆脱LIKE '192.168.2.1'
,因为它真的与='192.168.2.1'
相同
此外,您在结尾处设置LIMIT 100
意味着查询将针对所有记录运行,然后仅选择前100个 - 而是如何执行SELECT,其中仅涉及所有其他操作但不是LIKE并限制这个,然后有第二个SELECT使用LIKE?