我在名为“last_seen”的表列中有时间戳,如下所示:
2012-01-25 18:46:42
2012-01-23 08:19:04
2012-01-23 08:19:04
etc...
如何获取时间戳在当前时间戳10分钟内的所有记录(以最有效的方式)?
答案 0 :(得分:45)
最有效的方法是将时间戳(和时间戳,不使用其上的任何函数)与可以计算为每行的常量的表达式进行比较,这样mysql可以使用在timestamp列上定义的索引。
SELECT * FROM myTable
WHERE last_seen >= NOW() - INTERVAL 10 MINUTE
您始终可以尝试EXPLAIN SELECT ...
查看索引是否可用于查找满足WHERE条件的行,而无需检查表中的每一行。
答案 1 :(得分:3)
您的问题要求在当前时间戳的10分钟内记录,但我认为这意味着过去(不是将来)不超过十分钟:
SELECT col1, col2, col3
FROM table
WHERE DATE_ADD(last_seen, INTERVAL 10 MINUTE) >= NOW();
这会使last_seen
增加10分钟,并将其与当前时间进行比较。如果值更大,last_seen
小于十分钟前。
有关如何使用的说明,请参阅documentation on DATE_ADD()
。
答案 2 :(得分:0)
以防该方法对某些人无效。
在我在date()函数(由@karam qubsi建议)中添加timestamp列之前,以上答案中的“ where”条件对我而言不起作用:
SELECT * FROM myTable
日期(最后一次看到)的位置> = NOW()-间隔10分钟
只有那时我才开始获得正确的结果。
答案 3 :(得分:0)
对于希望将问题扩展到仅一张表之外并在过去(例如)5分钟内找到具有date_modified的数据库中任何表中任何条目的任何人,请尝试使用此脚本。
调整数据库条目(我使用了名为mgmt2go的数据库),并将下面的文件保存到可执行的.sql文件中。
根据情况进行自适应,但是,如果仅更改数据库设置,它将对数据库执行相同的操作。
我从命令行运行此SQL脚本,然后将结果输出到文件中,以便在调试将所有设置都写入MySQL(实际上是MariaDB)数据库的系统时,可以参考输出。我需要弄清楚通过系统用户界面进行更改时受到的影响。
# For this setup, it is best to send the output to a file
# and then read the file to see what records in what tables are found
# Save this file as list_tables.sql (or whatever you want to save it as)
# and use it by entering, at the CLI
# mysql --user=UserName --password=UserPassword -vv 2>&1 < path_to_executable_file/list_tables.sql > path_to_output_file/test.output.txt
# If you want the filename to include the time period,
# concatentate the bash date function with the filename
# ie: "mgmt2goDbaseChangesSince_"$(date +%Y-%m-%d_%H:%M:%S --date -'5 min')
# so the full sql comand would now look like
# mysql --user=UserName --password=UserPassword -vv 2>&1 < path_to_executable_file/list_tables.sql > "path_to_output_file/mgmt2goDbaseChangesFrom_"$(date +%Y-%m-%d_%H:%M:%S --date -'5 min')"_to_"$(date +%H:%M:%S)
# Set the delimeter so you can distingish the delimiter surrounding the Procedure
# (as an intact entity to be passed to the server)
# from the statements inside the Procedure calls
DELIMITER $$
# In case a previous script run created the procedure,
# delete it before running this script again
DROP PROCEDURE IF EXISTS `mgmt2go`.rc_list_tables_procedure$$
# Create a procedure to identify all the tables in the database
# (in this case, I have a database named mgmt2go)
# that contain multiple fields (id, date_modified) against which you want to search
CREATE PROCEDURE `mgmt2go`.rc_list_tables_procedure( IN rc_cutoff_date DATETIME )
BEGIN
# Always DECLARE in sequence: Variables, Cursors, Handler
# Variables
DECLARE rc_last_record BOOLEAN DEFAULT FALSE;
DECLARE rc_table_name varchar(64);
# Cursor
DECLARE rc_table_list CURSOR FOR SELECT DISTINCT `TABLE_NAME`
FROM `INFORMATION_SCHEMA`.`COLUMNS`
WHERE `INFORMATION_SCHEMA`.`COLUMNS`.`TABLE_SCHEMA` = 'mgmt2go'
AND `INFORMATION_SCHEMA`.`COLUMNS`.`COLUMN_NAME`
IN ( 'id' , 'date_modified' )
GROUP BY TABLE_NAME HAVING COUNT( DISTINCT COLUMN_NAME ) = 2
ORDER BY `INFORMATION_SCHEMA`.`COLUMNS`.`TABLE_NAME`;
# Handler
DECLARE CONTINUE HANDLER FOR NOT FOUND SET rc_last_record = TRUE;
# Activate the LOOP
OPEN rc_table_list;
rc_for_each_loop: LOOP
# Test if the previous iteration of the LOOP fetched the last record
# and if so, exit the LOOP
FETCH FROM rc_table_list INTO rc_table_name;
IF rc_last_record = TRUE THEN
LEAVE rc_for_each_loop;
END IF;
# Eliminate the entries in the job_queue table
# since they are just temporary system entries
IF rc_table_name = 'job_queue' THEN
ITERATE rc_for_each_loop;
END IF;
# Find all records in all tables with a date_modified field
# greater than or equal to the specified value in the CALL
# We cannot directly use a variable in a SELECT statement
# So we prepare a SELECT statement by concatenation
# and then use the Prepare and Execute functions to run the SELECT
SET @rc_query_for_modified := CONCAT(
'SELECT "' , rc_table_name , '" , `id` ,`date_modified` '
'FROM `mgmt2go`.`' , rc_table_name , '` '
'WHERE '
'TIMESTAMP( `mgmt2go`.`' , rc_table_name , '`.`date_modified` )'
' >= "' , rc_cutoff_date , '" '
);
PREPARE rc_test_modified_statement FROM @rc_query_for_modified;
EXECUTE rc_test_modified_statement;
DEALLOCATE PREPARE rc_test_modified_statement;
END LOOP rc_for_each_loop;
CLOSE rc_table_list;
END$$
# Reset the delimiter back to the default
DELIMITER ;$$
# Invoke the Procedure, providing the cutoff date = date record more current than
# You can provide an absolute time using
# CALL `mgmt2go`.rc_list_tables_procedure( "2019-01-02 16:49:28" );
# Or you can provide a time n (Seconds/Minutes/...) before a stated time (like NOW()
CALL `mgmt2go`.rc_list_tables_procedure( DATE_SUB( NOW() , INTERVAL 5 MINUTE ) );
# If you are also trying to see if any files have changed in the last n minutes
# and want to NOT search in a particular child directory (/cache in this case)
# at the CLI enter
# find path_to_directory -path path_to_child_directory_to_exclude -prune , -type f -mmin -120
# or
# find path_to_directory -mmin -120 -iname "*.*" | egrep -v "(child_directory_to_exclude)"
# where -120 is the number of minutes to look back (120 in this case)
# -mmin is minutes since modification and -cmin is minutes since creation
# -mtime is days since modification and -ctime is days since creation