How many times trigger in MySQL is called? - sql

I have a trigger on INSERT in MySQL 5.1. I want to know, how many times per second is it called. How can I do this?

Your best bet is to keep inserting into a table.
INSERT INTO trigger_log(query) VALUES(?)
This table has a datetime column that will automatically be updated, then you can do various queries to determine how many times/minute or hour, what period had the highest number of calls, etc.
Otherwise just update a table that has a column for day, hour, min, counter and just increment the counter for the current day/hour/min.
I don't like the second one as much as there is so much potential information being lost, but it would do what you want also.

There is no way to directly cound the number of triggers on the inserts. You could analyse the logfiles or you could alter your trigger (as the trigger acts on insert) to write an entry in a log table with auto_increment id and datetime. You can then analyze this table for any statistics.

Related

How many records were counted in specific day

Is it possible to check in DB2 how many records were counted in specific table in specific day in past
I have a table with name 'XYZ' and I would like to check row count for specific day e.g. for 10.09.2020, for 05.09.2020 and for 01.09.2020
In ordinary SQL, without special provisions, no, you canĀ“t!
Depending on your usage scenario, there are several ways to achieve this function. Here are three that I can think of:
If you table has a timestamp field or you can add one and you can guarantee there will be no rows deleted: You can just count the rows where the timestamp is smaller then your desired date. Cheap, performance wise, but deletes may make this impossible.
You could set up a procedure that runs daily and counts your rows to write them in a different table. This van also be rather cheap from a performance point of view, but you will be limited to the specific "snapshot" times you configured beforehand and you may have conditions where the count procedure did not run an therefore data is missing.
You could create an audit-table and a trigger on the table you are interested in to log every insert and delete operation on the table with a timestamp. This is the most performance heavy solution, but the only one that will give you always a full picture of the row count at any given time.

Ignore Unique Constraint and still insert other rows

I think I want the semantics of both UNIQUE and IGNORE_DUP_KEY.
I have an INSERT query that looks over recent data and inserts a unique key-value pair. It runs often and takes seconds at most.
I have another INSERT query that looks at all data and inserts unique key-value pairs. It takes minutes to run and probably finds nothing to do, except it will sometimes see the same data as the recent query, and will decide to insert the same pair.
I've implemented a UNIQUE constraint, so that's not a problem in itself, but I'd like other records determined by the long-running query to be inserted irrespective of the duplicates.
Both queries do explicitly have a clause similar to
WHERE NOT EXISTS (SELECT Key, Value From TargetTable TT
WHERE TT.Key = Result.Key AND TT.Value = Result.Value)
If I understand correctly, you want something like MySQL's INSERT IGNORE. I don't believe this functionality exists in SQL Server. Your specific problem appears to be updates on this (or another table) that occur during the updating process, introducing duplicate keys.
One option is to put a lock on the table during this operation, not allowing any other operations. That is probably not feasible given the time frame for the lock.
Another option is to take the long running query and stash the results into a temporary table. Then, do the inserts from this table, one at a time, capturing and ignoring any violations of the unique constraint.
I've decided to split the second query into two so that I now have three queries:
Quick 15 minute past query running every 30 seconds.
Nearly as quick query looking back to midnight UTC; may have duplicate key failures but retrying won't take long; runs every 2 minutes.
Slow query reviewing all data, but ignoring the current UTC day; won't have duplicate key failures; runs twice a day.

How to truncate and add new rows to the table with a select query never getting empty results

I have a requirement where a table holds the state of certain things.
This table is truncated and new status data in inserted in it every second.
The problem is that if a select query is executed between a delete and the following insert, the user will get empty table in return.
SQL Transactions would not help here i think but not sure.
Also, if the select query is executed between the delete and insert query, it shouldn't return error because its blocked by a database lock. it should just wait till the delete + insert operation is finished.
What would be the best way to implement such a system?
How should i form the "delete + insert" query and the "select" query?
Thank you in advance.
--------additional information
This table would be result of a multiple heavy queries and will be updated every second so that the applications do not run those heavy queries and instead, they would get the required information from this table.
so a truncate and insert every second and multiple selects at random.
Don't truncate the table. Instead, insert the new status using an identity primary key or the date as the primary key. Then do:
select top 1 date
from table
order by date desc
or
select max(date)
from table
(These should have basically the same execution plan.)
Then, you insert the new date. When the insert is done, the data is immediately available.
You can then delete older rows at your leisure.
From your description, this table always contains only one row, the last status change. The contents changes about every second, apparently 24 hours a day.
Rather than change the data with a truncate/insert pair of operations, why not just update the one row? One operation, no race condition, no locking conflicts at all.
There is even a way to do that without changing any existing code:
Rename the table
Create a view which shows the row from the renamed table. Name it the original table name.
Create an "instead of insert" trigger on the view. The trigger performs an update to the table rather than an insert. This could be performed with a merge statement which will work if the table should ever happen to be empty.
Oops, I was wrong. You would still have to change the code to remove the truncate statement. It will not work against the view but it will throw an exception. Unfortunately, you can't intercept the truncate with a trigger and simply ignore it.
Then when the insert is executed, a truncate is no longer necessary and the insert converted into an update (or merge). One operation.

SQL - When was my table last change?

I want to find when the last INSERT, UPDATE or DELETE statement was performed on a table (for now, in the future I want to do this in multiple tables) in an Oracle database.
I created a table and then I updated one of its rows. Now I've the following query:
SELECT SCN_TO_TIMESTAMP(ora_rowscn) from test_table;
This query returns the timestamps of each row, and for each of them it gives the time when they were first created.
But the row that I've updated have the same timestamp as the others. Why? Shouldn't the timestamp be updated?
ORA_ROWSCN is not the right solution for this. It is not necessarily reliable at the row level. Moreover, it's not going to be useful at all for deleted rows.
If you have a real need to know when DML changes were made to a table, you should look at Oracle's auditing feature.
An alternative is to use triggers to record when changes are made to the table. Since you say you only care about the time of the most recent change, you can just create a single-column table to record the time, and write a trigger that fires on any DML statement to maintain it. If you're doing this in a production environment or even just in one where more than one session might be modifying the table, you'd want to think about how it should work when concurrent changes are made. You could force the table to have at most one row, but that would serialize every change to the table. You could allow each session to insert a separate row and take the max value when querying it, but then you probably want to think about clearing out old rows from time to time.

collecting mysql statistics

What would be the easiest way to count the new records that are inserted into a database? Is it possible to include a count query in with the load query?
Or is something more complex needed, such as recording the existing last record and counting everything added after it?
edit:
I have a cron job, that uses LOAD DATA INFILE in a script that is passed directly to mysql. This data is used with a php web application. As part of the php web application, I need to generate weekly reports, including how many records were inserted in the last week.
I am unable to patch mysql, or drastically change the database schema/structure, but I am able to add in new tables or fields. I would prefer not to count records from the csv file and store this result in a textfile or something. INstead, I would prefer to do everything from within PHP with queries.
Assuming your using Mysql 5 or greater, you could create a trigger which would fire upon inserting into a specific table. Note that an "insert" trigger also fires with the "LOAD" command.
Using a trigger would require you to persist the count information in a separate table. Basically you'd need to create a new table with 1 row/column to hold the count. The trigger would then update that value with the amount of data loaded.
Here's the MySQL manual page on triggers, the syntax is fairly straight forward. http://dev.mysql.com/doc/refman/5.0/en/create-trigger.html
edit
Alternatively, if you don't want to persist the data within the database you could perform your "Load" operations within a stored procedure. This would allow you to perform a select count() on the table before you begin the Load and after the Load is complete. You would just need to subtract the resulting values to determine how many rows were inserted during the Load.
Here's the MySQL manual page on procedures.
http://dev.mysql.com/doc/refman/5.0/en/create-procedure.html
That would probably depend on what is determined as being new. Is it entries entered into the database in the last five minutes or 10 minutes etc? Or is it any record past a certain Auto ID?
If you are looking at time based method of determining what's new, you can have a field (probably of type datetime) that records the time when the record was inserted and to get the number, you simply do a...
select count(*) from table where currentTime > 'time-you-consider-to-be-new'
If you don't want to go by recording the time, you can use an auto increment key and simply keep track of the last inserted ID and count the ones that come after that at any given time window. so if one hour ago the ID was 10000 then a number of records have been inserted since then. You will need to count all records greater than 10000 and keep track of the last insert ID and repeat whenever needed.
If you are not looking at a specific table, you can use the following:
show global status like "Com_%";
This will show you statistics for every type of query. These numbers just keep on counting, so if you want to use them, record the initial number when starting to track the queries, and subtract this from your final number (but yea, that's a given).
If you are looking for pure statistics, I can recommend using Munin with the MySQL plugins.
From where do you load the data? You might consider to count them befor you insert them into the database. If it's a sqlscript you might write a quick and dirty bash script (with grep or something similar) to count the fields.
You say you can't change the structure. Does that mean you can't change the table you are inserting into, or you can't change the database at all? If you can add a table, then just create a table with 2 columns - a timestamp and the key of the table you are loading. Before you load your csv file, create another csv file with just those two columns, and load that csv after your main one.
This might be simpler than you want, but what about a Nagios monitor to track the row count? (Also consider asking around on serferfault.com; this stuff is totally up their alley.)
Perhaps you could write a small shell script that queries the database for the number of rows. You could then have a Cron job that runs every minute/hour/day etc and outputs the COUNT to a log file. Over time, you could review the log file and see the rate at which the database is growing. If you also put a date in the log file, you could review it easier over longer periods.
See if this is the kind of MySQL data collection you're interested in: http://code.google.com/p/google-mysql-tools/wiki/UserTableMonitoring.
If that is the case, Google offers a MySQL patch (to apply to a clean mysql directory source) at http://google-mysql-tools.googlecode.com/svn/trunk/mysql-patches/all.v4-mysql-5.0.37.patch.gz. You can read more about the patch at http://code.google.com/p/google-mysql-tools/wiki/Mysql5Patches.
If this is not what you're looking for, I suggest you explain yourself a little more in order for us to help you better.
Could you use a trigger on the table which will insert into a table you created, which in the structure has a timestamp?
You could then use a date calculation on a period range to find the information needed.
I dont know what version of mysql you are using, but here is link to the syntax for trigger creation in version 5.0: http://dev.mysql.com/doc/refman/5.0/en/create-trigger.html
Good luck,
Matt
Well, if you need exhaustive information: which rows were inserted, updated or deleted, it might make sense to create an additional audit table to store those things with a timestamp. You could do this with triggers. I would also write a stored procedure which would execute as event and erase old entries (whatever you consider old).
Refer to the link posted by Lima on how to create triggers in MySQL.
Refer to page 655 of "MySQL Cookbook" by Paul Dubois (2nd Edition) or page 158 of "SQL for smarties" by Joe Celko.
so the 'load' will only insert new data in the table ? or rewrite the whole table ?
If it will load new data, then you can do a select count(*) from yourtable
once before the loading and once after the loading ... the difference will show you how many new records where inserted..
If on the other hand you rewrite the whole table and want to find the different records from the previous version .. then you would need a completely different approach..
Which one is it ?
Your question is a bit ambiguous but they mysql c APIs provide a function "mysql_affected_rows" that you can call after each query to get the number of affected rows. For an insert it returns the number of rows inserted. Be aware that for updates it returns the number of rows changed not the number of rows that matched the where clause.
If you are performing a number of queries and need to know how many were inserted the most reliable way would probably be doing a count before and after the queries.
As noted in sobbayi's answer adding a "created at" timestamp to your tables would allow you to query for records created after (or before) a given time.
UPDATE:
OK here is what you need to do to get a count before and after:
create a table for the counts:
create table row_counts (ts timestamp not null, row_count integer not null);
in your script add the following before and after your load file inline query:
insert into row_counts (ts,row_count) select now(),count(0) from YOUR_TABLE;
load file inline......
insert into row_counts (ts,row_count) select now(),count(0) from YOUR_TABLE;
the row_counts table will now have the count before and after your load.
show global status like 'Com_insert';
flush status and show session status... will work for just the current connection.
see http://dev.mysql.com/doc/refman/5.1/en/server-status-variables.html#statvar_Com_xxx
Since you asked for the easiest way, I would suggest you to use a trigger on insert. You could use a single column, single row table as a counter and update it with the trigger.