我不习惯MySQL,但我认为它可能比它快得多。
这是我的表:
CREATE TABLE `crashes` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`added_date` int(11) NOT NULL,
`status` int(11) NOT NULL,
`issue_id` varchar(32) NOT NULL,
`report_id` text NOT NULL,
`app_version_code` text NOT NULL,
`app_version_name` text NOT NULL,
`package_name` varchar(80) NOT NULL,
`package_name_id` tinyint(4) NOT NULL,
`file_path` text NOT NULL,
`phone_model` text NOT NULL,
`android_version` text NOT NULL,
`build` text NOT NULL,
`brand` text NOT NULL,
`product` text NOT NULL,
`total_mem_size` int(11) NOT NULL,
`available_mem_size` int(11) NOT NULL,
`custom_data` text NOT NULL,
`stack_trace` text NOT NULL,
`initial_configuration` text NOT NULL,
`crash_configuration` text NOT NULL,
`display` text NOT NULL,
`user_comment` text NOT NULL,
`user_app_start_date` text NOT NULL,
`user_crash_date` text NOT NULL,
`dumpsys_meminfo` text NOT NULL,
`dropbox` text NOT NULL,
`logcat` text NOT NULL,
`eventslog` text NOT NULL,
`radiolog` text NOT NULL,
`is_silent` text NOT NULL,
`device_id` text NOT NULL,
`installation_id` text NOT NULL,
`user_email` text NOT NULL,
`device_features` text NOT NULL,
`environment` text NOT NULL,
`settings_system` text NOT NULL,
`settings_secure` text NOT NULL,
`shared_preferences` text NOT NULL,
`application_log` text NOT NULL,
`media_codec_list` text NOT NULL,
`thread_details` text NOT NULL,
`user_ip` text NOT NULL,
PRIMARY KEY (`id`),
KEY `package_name_id` (`package_name_id`)
) ENGINE=MyISAM AUTO_INCREMENT=202364 DEFAULT CHARSET=utf8
正如你所看到的,它充满了200k行。我想检索行added_date
(unix时间戳,int(11)
)和当天的行数。
所以我选择日期,日期(作为Y-M-D),并计算:
SELECT date_format(from_unixtime(added_date), '%Y-%c-%d') as date, added_date, count(*) as nb_crashes FROM crashes WHERE package_name = 'net.bicou.redmine' GROUP BY date ORDER BY date ASC
这很慢!在我的主机上的专用mysql服务器上差不多1.5秒。
所以我想我可以稍微优化一下:我添加了一个tinyint
的package_name_id,每个package_name
都是唯一的(我有5个不同的package_name
值200k行)。我做了INDEX
,以便MySQL可以更快地浏览它
结果:0.9秒。那要好得多,但仍然没有我期待的表现!
我怎样才能优化它?我想在每一行创建日期,然后分组是非常昂贵的。但是我不知道如何才能让它更快......
编辑:
以下是我更新表格所做的事情:
ALTER TABLE `crashes` ADD `temp` DATETIME NOT NULL
UPDATE crashes SET temp = FROM_UNIXTIME( added_date )
ALTER TABLE `crashes` ADD INDEX ( `temp` )
这是更新的查询:
SELECT added_date, count(*) as nb_crashes FROM crashes WHERE package_name_id=3 GROUP BY year(temp),month (temp),dayofmonth(temp) ORDER BY temp ASC
我的执行时间大约是一秒钟......我做错了什么?
答案 0 :(得分:2)
如果您需要以类似日期的方式查询该字段,则不应使用unix时间戳值。您应该使用日期,日期时间或时间戳字段类型。
为什么?
因为如果您希望按日期执行特定日期或组记录的查询结果,您将始终必须使用FROM_UNIXTIME()
才能执行此操作。如果您尝试将其用于排序,联接,过滤器,组等,则此函数调用将阻止您对日期值使用任何类型的索引。除了使用正确的内容之外,您无法做任何事情来改善查询数据类型,然后索引您将用于排序,过滤器,联接,组等的字段。
真的在DB中使用unix时间戳似乎是由经验不足的PHP开发人员激增的,他们认为在PHP中使用这种格式的日期更容易(他们懒得将日期/日期时间DB输出转换为unix时间戳)在PHP中,或者他们还没有弄清楚如何使用dateTime和dateInterval PHP类来简化PHP中的日期工作。
我的建议是立即打破这种习惯,开始学习如何使用MySQL中的日期/日期时间字段。
另一件事我建议你看看你的表DDL是你可能应该重新审视那里的文本字段的使用。大多数情况看起来最好是varchar字段。
答案 1 :(得分:1)
如果您需要性能,则需要索引,如果需要索引,则需要在进行查询之前创建一个包含正确数据类型的列。
这需要创建一个额外的列并使用转换结果填充它,并插入正确填充该列的所有新行。
为什么要将日期存储为时间戳而不是正确的DATE
列?
答案 2 :(得分:0)
您可以在package_name
和added_date
列上创建索引。另外,请将ORDER BY
更改为added_date
而不是date
,因为按date
排序可能需要一个文件排序步骤。
在任何情况下EXPLAIN
都有助于更好地诊断查询。