I have a mysql table which has ‘username’, ‘acctstarttime’ and ‘acctstoptime'(and an ‘id’) datetime columns. I need to get records that its acctstarttime or acctstoptime between other ‘acctstarttime’ and ‘acctstoptime’ records with same username. For example ‘John’ has 3 records.
id | username | acctstarttime | acctstoptime |
---|---|---|---|
1 | John | 29.12.2022 | 01.01.2023 |
2 | John | 30.12.2022 | 03.03.2023 |
3 | John | 12.12.2022 | 14.12.2022 |
Second rows acctstarttime is between first rows acctstarttime and acctstoptime and first rows acctstoptime is between second rows acctstarttime and acctstoptime. I want to query that 2 records.
I can do it with php but it takes about 3-4 days or more for 1 million records. I have very inefficient function.
How can i reduce this time in mysql or php(just speed up)?
I downloaded each record to different files based on username. I wrote this laravel code but it works too slow. It can be confusing.
function findRecordsBetweenSameHours()
{
$directory = storage_path() . "/app/";
$files = Storage::files('usernames');
foreach ($files as $file) {
$records =json_decode(file_get_contents($directory . $file), true);
foreach ($records as $record) {
$record["acctstarttime"] = Carbon::createFromFormat('Y-m-d H:i:s', $record["acctstarttime"]);
$record["acctstoptime"] = Carbon::createFromFormat('Y-m-d H:i:s', $record["acctstoptime"]);
foreach ($records as $record2) {
$record2["acctstarttime"] = Carbon::createFromFormat('Y-m-d H:i:s', $record2["acctstarttime"]);
$record2["acctstoptime"] = Carbon::createFromFormat('Y-m-d H:i:s', $record2["acctstoptime"]);
if (
($record2["acctstoptime"]->between($record["acctstarttime"], $record["acctstoptime"], false)
|| $record2["acctstarttime"]->between($record["acctstarttime"], $record["acctstoptime"], false)
)
&& $record2["acctsessionid"] != $record["acctsessionid"]
) {
Storage::append('x.log',
$record["acctsessionid"] . " - " . $record2["acctsessionid"] . " - " . $record["username"]
);
}
}
}
}
Storage::append('x.log',
"finish"
);
}
2
Answers
You can write query like this
As I understand your question, you want records for which another record exists with the same user name and an overlapping period of time.
I would recommend
exists
and a few inequality conditions:For each row, the subquery searches for an "overlapping" record of the same user, and filters in rows that match. The inequality conditions on the start and end time qualify the date range overlap.
An index on
(id, acctstarttime, acctstoptime)
might help performance.