PERSIST vs PERSIST_ONLY (MySQL) - mysql

I read Syntax for Persisting System Variables in MySQL documentation about PERSIST and PERSIST_ONLY as shown below:
To persist a global system variable to the mysqld-auto.cnf option file in the data directory, precede the variable name by the PERSIST keyword or the ##PERSIST. qualifier:
SET PERSIST max_connections = 1000;
SET ##PERSIST.max_connections = 1000;
To persist a global system variable to the mysqld-auto.cnf file without setting the global variable runtime value, precede the variable name by the PERSIST_ONLY keyword or the ##PERSIST_ONLY. qualifier:
SET PERSIST_ONLY back_log = 100;
SET ##PERSIST_ONLY.back_log = 100;
It seems like PERSIST sets a global variable runtime value but PERSIST_ONLY doesn't set a global variable runtime value but I don't understand what a global variable runtime value is, so I don't really understand the difference between PERSIST and PERSIST_ONLY.
My questions:
What is the global variable runtime value?
What is the difference between PERSIST and PERSIST_ONLY?

what the global variable runtime value is .. what is the difference between PERSIST and PERSIST_ONLY?
There exists a bunch of global option variables which effects the server. They effects the whole server. Changing the variable value changes the server behavior immediately.
Option variables values are loaded from option files during server start. If some option have no according row in the file then hardcoded default value is used.
Option variables are not reloaded when the server works. Changing the setting in the options file does not effect the server until it restarts.
So when you use PERSIST then new value is written into the option file (and it will be applied during the next server start) and is set to current server settings (the server alters its work according this new setting).
When you use PERSIST_ONLY then new value is written into the option file (and it will be applied during the next server start) but it is not set to current server settings (and current server behavior is not changed).

To set a global variable runtime value, PERSIST doesn't need to restart MySQL while PERSIST_ONLY needs to restart MySQL.
For example, a global variable runtime value is "max_connections" which is "151" by default as shown below:
mysql> SELECT ##GLOBAL.max_connections;
+--------------------------+
| ##GLOBAL.max_connections |
+--------------------------+
| 151 |
+--------------------------+
Now, with PERSIST, if setting "500" to "max_connections" as shown below:
mysql> SET PERSIST max_connections = 500;
Then, "max_connections" is now "500" as shown below:
mysql> SELECT ##GLOBAL.max_connections;
+--------------------------+
| ##GLOBAL.max_connections |
+--------------------------+
| 500 |
+--------------------------+
But with PERSIST_ONLY, if setting "500" to "max_connections" as shown below:
mysql> SET PERSIST_ONLY max_connections = 500;
Then, "max_connections" is still "151" as shown below:
mysql> SELECT ##GLOBAL.max_connections;
+--------------------------+
| ##GLOBAL.max_connections |
+--------------------------+
| 151 |
+--------------------------+
Then, stop, start and login MySQL again:
C:\Windows\System32>net stop MySQL80 && net start MySQL80 && mysql -u root -p
Then finally, "max_connections" is now "500" as shown below:
mysql> SELECT ##GLOBAL.max_connections;
+--------------------------+
| ##GLOBAL.max_connections |
+--------------------------+
| 500 |
+--------------------------+
1 row in set (0.00 sec)

Related

System variable change doesn't work [duplicate]

I ran the command as root:
set ##auto_increment_offset = 2;
But the effect cannot be seen from other connections. Why not? It is global.
From http://dev.mysql.com/doc/refman/5.1/en/replication-options-master.html:
"If the global value of either variable is set, its effects persist until the global value is changed or overridden by setting the session value, or until mysqld is restarted."
That doesn't seem to agree with what I am seeing.
Ultimately, I would like to know if there any way to permanently set the offset for all clients without restarting mysqld?
As per MySQL documentation you need to set values of auto_increment_offset for both GLOBAL and SESSION.
SET GLOBAL auto_increment_offset = 2;
SET SESSION auto_increment_offset = 2;
SHOW VARIABLES LIKE '%auto_increment_offset%';
If the global value of either variable is set, its effects persist until the global value is changed or overridden by setting the session value, or until mysqld is restarted. If the local value is set, the new value affects AUTO_INCREMENT columns for all tables into which new rows are inserted by the current user for the duration of the session, unless the values are changed during that session.
To set it globally you should add prefix 'GLOBAL' or '##global.'. For example -
SET ##GLOBAL.auto_increment_offset = 2;
The '##' is the same as 'SESSION' or '##session.', it sets session variable.
Using System Variables.

Data truncation: Data too long for column 'processed' at row 1 even after disabling strict mode

I'm getting UPDATE billing2.fct_calls SET processed = 'false': Data truncation: Data too long for column 'processed' at row 1, even after disabling strict mode.
This is what my db shows from another connection, while im getting the error above from connections made by an application:
+-----------------------------------------------------------------------------------------------------------------+
| ##sql_mode |
+-----------------------------------------------------------------------------------------------------------------+
| IGNORE_SPACE,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+-----------------------------------------------------------------------------------------------------------------+
Could be you are using string instead of boolean
try using
UPDATE billing2.fct_calls SET processed = false
and if you need to disable strict mode with the
[mysqld]
sql_mode=IGNORE_SPACE,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
remember to restart the dbengine

PHPMyAdmin forces to use ut8mb4 as default collation

Ok, so I've spent the morning trying to change the default collation on my XAMPP setup.
Here's the problem: I'm using Format() in a view, to convert a double into a string
CREATE VIEW `test` AS
SELECT
Format(some_data_table.double_number,0) AS string_result
FROM some_data_table;
When I look at the returned column, its showing as utf8mb4_general_ci.
I've tried all manner of settings in my.ini and phpMyAdmin's config.inc.php
to no avail.
As a last resort, I'm prepared to add the collation parameter to view.
I'd be grateful for any tested solution
Ok - i'm going to post my own answer for anyone else who lands here:
(i had seen this somewhere else, but didn't trust it a t the time because there was no explanation).
When the SQL Format() turns a number into a string, it uses the variable character_set_results.
PMA's Variables Tab was showing this as "utf8" but then on a line below, it was saying (session value) = utf8mb4.
So i was aware that PMA was overriding the server default.
My real problem was that I could find no way to change this override - either by using the [mysqld] skip-character-set-client-handshake setting.. or by editing the php.config.inc file.
Today I had a breakthrough.. I established that if I used the same PMA to connect to and older MySQL server, the problem did not occur.
This suggested to be that PMA was forcing utf8mb4 on newer (capable) servers, but not older ones.
I did a text search of phpmyadmin for the string 'mb4' and found the following code in the class: phpMyAdmin/libraries/DatabaseInterface.class.php
// Skip charsets for Drizzle
if (!PMA_DRIZZLE) {
if (PMA_MYSQL_INT_VERSION > 50503) {
$default_charset = 'utf8mb4';
$default_collation = 'utf8mb4_general_ci';
} else {
$default_charset = 'utf8';
$default_collation = 'utf8_general_ci';
}
the PMA_MYSQL_INT_VERSION > 50503 seems to fit with my theory about older mysql versions, so i've backed up the file and edited the class replacing utf8mb4 with utf8 in this function.
phpMyAdmin is now showing what i want in its variables tab, and the Format() function is now returning what i expect.
(I won't give you a tested solution without a failing test case.)
Here's a possible explanation:
mysql> SELECT FORMAT(2e7, 0);
+----------------+
| FORMAT(2e7, 0) |
+----------------+
| 20,000,000 |
+----------------+
But you are working in a "locale" where the "thousands separator" is ., not ,.
The solution has nothing to do with COLLATION. Instead, look at the arguments to FORMAT().
mysql> SELECT FORMAT(2e7, 0, 'de_DE');
+-------------------------+
| FORMAT(2e7, 0, 'de_DE') |
+-------------------------+
| 20.000.000 |
+-------------------------+
I am guessing that MS Access and MySQL are assuming different "Locales", hence stumbling over the thousands separator, and possibly other differences.
References on Locale:
http://dev.mysql.com/doc/refman/5.7/en/locale-support.html
http://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_lc_time_names

Permanently setting auto_increment_offset in MySQL

I ran the command as root:
set ##auto_increment_offset = 2;
But the effect cannot be seen from other connections. Why not? It is global.
From http://dev.mysql.com/doc/refman/5.1/en/replication-options-master.html:
"If the global value of either variable is set, its effects persist until the global value is changed or overridden by setting the session value, or until mysqld is restarted."
That doesn't seem to agree with what I am seeing.
Ultimately, I would like to know if there any way to permanently set the offset for all clients without restarting mysqld?
As per MySQL documentation you need to set values of auto_increment_offset for both GLOBAL and SESSION.
SET GLOBAL auto_increment_offset = 2;
SET SESSION auto_increment_offset = 2;
SHOW VARIABLES LIKE '%auto_increment_offset%';
If the global value of either variable is set, its effects persist until the global value is changed or overridden by setting the session value, or until mysqld is restarted. If the local value is set, the new value affects AUTO_INCREMENT columns for all tables into which new rows are inserted by the current user for the duration of the session, unless the values are changed during that session.
To set it globally you should add prefix 'GLOBAL' or '##global.'. For example -
SET ##GLOBAL.auto_increment_offset = 2;
The '##' is the same as 'SESSION' or '##session.', it sets session variable.
Using System Variables.

Adjusting for the default time-zone setting on RDS

We recently switched to an RDS instance and noticed that bunch of our database tasks were getting triggered 4 hours earlier than needed. On investigating further, the problem is caused by the default time-zone setting (UTC) on the RDS instance. Since this setting can not be altered, we would like to fix the issue on the code level globally across all our applications using this database instance. I tried to set the time-zone on the db instance I create to 'US/Eastern' by using
set GLOBAL time_zone = 'US/Eastern'" OR
set time_zone = 'US/Eastern'"
But that generates an error "Database error: Unknown or incorrect time zone: 'US/Eastern'"
What do you think I am doing wrong here? Does anyone has used any other solutions ?
Unfortunately it's not possible to set the default_timezone in the RDS DB ParameterGroups so your attempt was the right direction already.
$ rds-describe-db-parameters default | grep "time_zone"
DBPARAMETER default_time_zone engine-default string static false
To set the global value via SET GLOBAL you need to have the SUPER privilege which is not granted to you as a RDS user.
The only way to set the time_zone is on a per-connection basis
mysql> SET time_zone = timezone;
On my machines I've tried US/Eastern successfully but I got a quite old generation running.
To determine the timezones you have available log into your box
mysql -h yourboxhost.rds.amazonaws.com -u <youruser> -p
and type
mysql> SELECT * FROM mysql.time_zone_name;
You should get a list of installed and valid timezone names you can set on your instance
+----------------------------------------+--------------+
| Name | Time_zone_id |
+----------------------------------------+--------------+
| Africa/Abidjan | 1 |
| Africa/Accra | 2 |
| Africa/Addis_Ababa | 3 |
| Africa/Algiers | 4 |
| Africa/Asmara | 5 |
| Africa/Asmera | 6 |
| Africa/Bamako | 7 |
| Africa/Bangui | 8 |
| Africa/Banjul | 9 |
| Africa/Bissau | 10 |
| Africa/Blantyre | 11 |
| Africa/Brazzaville | 12 |
| Africa/Bujumbura | 13 |
| Africa/Cairo | 14 |
etc...
You have to set the time_zone each time you connect to your database server
For example if you use the php Mysqli extension you can do this
$mysqli = mysqli_init();
mysqli_options($mysqli,MYSQLI_INIT_COMMAND,"SET time_zone = 'Africa/Brazzaville'" );
mysqli_real_connect($mysqli,$host, $user, $pass,$dbName) or die ('Unable to connect');
Otherwise just manually ( in terms of let your database connector do it ) execute the SET time_zone = '<YOUR_DESIRED_TIMEZONE>' Query right after you've connected to your database
The time_zone setting of RDS database instances can now be modified: https://aws.amazon.com/de/premiumsupport/knowledge-center/rds-change-time-zone/
I did the following steps, So that I could change the timezone
login to RDS and Create New Parameter Group.
Edit the newly created Parameter Group
Set timezone Ex:Asia/Calcutta and Save Changes
Modify RDS instance, change DB's Parameter Group to newly created parameter group
Save And Reboot RDS instance
tldr;
Create a "shared" schema that all your users have EXECUTE access to, create a SPROC that modifies the session timezone and modify the init_connect MySQL parameter to call it.
As Ryan Weir pointed out in his excellent answer in a duplicate question this should probably be avoided if possible. If, however, you are like me and want to implement it for the sake of convenience and sanity then I took Ryan's solution and made a few modifications.
If you have multiple users setup in MySQL with varying permissions then simply putting the sproc in the mysql schema might have problems. To solve this I created a new schema called "shared" and gave all my users EXECUTE access to this schema. I then created the following stored procedure.
DROP PROCEDURE IF EXISTS shared.store_time_zone;
CREATE PROCEDURE shared.`store_time_zone`()
IF NOT (POSITION('rdsadmin#' IN CURRENT_USER()) = 1) THEN
SET SESSION time_zone = 'US/Pacific';
END IF;
I prefer to set 'US/Pacific' to handle daylight savings but you should test this to make sure your MySQL instance recognizes it first. Just execute the following query SET SESSION time_zone = 'US/Pacific'; to make sure it works. To look up your timezone execute SELECT * FROM mysql.time_zone_name;
At this point I recommend testing the permissions before you go modifying the paramter group and potential break everything. Simply connect to the DB (preferably with a user that has low level permissions and/or is commonly used) and execute the following queries.
CALL shared.store_time_zone;
select now();
Hopefully you didn't get any errors and the correct time showed up.
Next you will need to modify the init_connect parameter in the DB Parameter Group that your RDS instance is using. You can do this in the RDS web console, through the API or the command line utility. If you use the command line it will look like this:
$ rds-modify-db-parameter-group PARAMGROUP --parameters "name=init_connect, value='CALL shared.store_time_zone', method=immediate"
If you do it through the web console then you just need to change the value of init_connect.
CALL shared.store_time_zone
Go back to your RDS instance in the web console and scroll the details pane down to the DB Parameter Group. It should say something like (applying) or (in-sync). Once it is (in-sync) go test everything out to make sure there are no problems.
If at this point you run into problems and need to roll things back then I recommend setting the init_connect value to something harmless like:
SET SESSION time_zone = '-00:00';
Setting it back to blank is impossible to do from the web console. See this thread for more details on why one can't restore the empty value for the DB parameter
#Thomas Paine's solution works for me except I had to user user() instead of current_user() as inside the context of init_connect current_user() returns the master RDS user. (By master I do not mean rdsadmin which is the real root user but the user created with the DB instance with most privileges.)