Quantcast
Channel: Planet MySQL
Viewing all 18816 articles
Browse latest View live

FOSDEM: Histogram support in MySQL 8.0

$
0
0

The slides and video from my FOSDEM presentation on histogram support in MySQL can now be downloaded.  Check it out if you want to learn more about how you can create histograms to improve query plans in MySQL 8.0.

The presentation shows you how to create histograms over column values, 
presents the types of histograms you can create, and discusses best practices for using histograms.

Prior to MySQL 8.0, the query optimizer lacked statistics on columns that are not indexed.  With histograms the query optimizer will be able to make more accurate selectivity estimates for conditions on such columns.   With better estimates, the query optimizer can produce better query plans, especially for join queries.  Check out the presentation for a couple of examples of join queries that runs faster due to histograms!



The confusing strategy for MySQL shell

$
0
0

Where the hell is it?

The MySQL shell is a potentially useful tool that has been intentionally made difficult to use properly.

It was introduced, with much fanfare, with the MySQL Document Store, as THE tool to bridge the SQL and no-SQL worlds. The release was less than satisfactory, though: MySQL 5.7.12 introduced a new feature (the X-protocol plugin) bundled with the server. The maturity of the plugin was unclear, as it popped out of the unknown into a GA release, without any public testing. It was allegedly GA quality, although the quantity of bug reports that were filed soon after the release proved otherwise. The maturity of the shell was known as "development preview", and so we had a supposedly GA feature that could only be used with an alpha quality tool.

The situation with the MySQL shell got worse in a few months. A new product was brewing (MySQL Group Replication) and went rapidly from something released in the Labs without docs to being part of the regular server distribution, and it was evolving into a more complex and ambitious project (the InnoDB Cluster) which used the MySQL shell as its main tool.

Since the announcement of InnoDB Cluster, using the MySQL shell has been a nightmare. You saw examples in blog posts and presentations, and when you tried them at home, they did not work. There were different releases of MySQL shell with the same version number but different capabilities, depending on whether they were released through the main downloads site or through the labs.

When I asked why the shell wasn't distributed with the server, like the other tools, I was told that a non-GA product could not be released with a GA server. Considering that the Document Store is still walking around with a Pre-Production status legal notice, this was an odd excuse.

Still, I kept waiting, trying to figure out how to pair a given version of MySQL shell with a given version of the server. Unlike the server, there are no release notes for the shell, so every release was a surprising experience.

Eventually, the MySQL shell reached the GA state, with which merit I can't tell. Given the obstacles in the path to its usage, I doubt it has had any serious testing from the community. Despite the state being GA, it keeps being released separately, leaving the puzzled users with the ungrateful task of determining with which server version that shell could be used safely.

With the upcoming release of MySQL 8.0, a new version of MySQL shell appeared, with a colorful prompt and new features that the GA shell doesn't have. The public perception of the tool keeps getting more confused. In the presentations given by the MySQL team we see the new shell doing wonders, while the GA shell keeps its monochromatic features. Shall I use the 8.0.x shell with a 5.7 server or should I stick with the 1.0 version?

In MySQL 8.0, the situation is still divided. Both products (the server and the shell) are, as of today, not GA yet. It would make sense to finally end the craziness and put the two things together, so that users don't have to hunt around for the right shell version. But the two products are still released separately.


How can I do stuff with MySQL shell?

So far, we have only seen the availability of the shell. What about the functionality?

I have heard that Oracle wants to convert the shell into the only tool to deal with MySQL. I can't prove it, as Oracle doesn't release its development plans to the public, but I can see the emphasis on the shell in talks and articles authored by MySQL team engineers. If this is the plan, I think it needs a lot more work.

If you try to use MySQL shell the same way as the regular "mysql" client, you get in trouble soon.

mysqlsh --user root --password=msandbox --port=5721 --host 127.0.0.1
mysqlx: [Warning] Using a password on the command line interface can be insecure.
Creating a Session to 'root@127.0.0.1:5721'
Your MySQL connection id is 38
Server version: 5.7.21 MySQL Community Server (GPL)
No default schema selected; type \use to set one.
MySQL Shell 1.0.11

Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type '\help' or '\?' for help; '\quit' to exit.

Currently in JavaScript mode. Use \sql to switch to SQL mode and execute queries.

I see two problems here:

  • The warning about the password on the command line is legitimate. The trouble is that there is no alternative. mysqlsh does not support --defaults-file, and there is no way of giving a password other than directly at invocation. There is an option "--passwords-from-stdin" which does not seem to work, and even if it did, I can't see the advantage of using the password from a pipe.
  • The default mode is Javascript. I can see that this makes operations simpler when you want to perform setup tasks for InnoDB Cluster, but certainly doesn't help me to use this tool as the primary drive for database management. There is a "--sql" option that does what I expect, but if this is not the default, I can't see this replacement being very successful.
  • Due to the previous items, using the tool in batch mode (with -e "SQL commands") is impossible, as every invocation will start with the freaking password warning.

I'm afraid that it's too late to take action for MySQL 8.0. The MySQL team is probably packaging the GA release while I write these notes. But I offer some suggestions nonetheless.


Wish list


  1. Package MySQL shell with the server. Past experience shows that the MySQL team keeps adding features into a GA release, thus exposing users to the risk of getting the wrong tool for the job. Having the shell and the server in the same tarball will help users pick the right version for the task. This is similar to what happens with mysqldump: using the tool from 5.5 with a 5.7+ server will not work properly. There is no reason for mysqlsh to be treated differently.
  2. Make sure that all the features of the mysql client work seamlessly in mysqlsh. Perhaps run the test suite replacing mysql with mysqlsh and pick up from there.
  3. Make the MySQL shell compatible with other tools. Specifically, it should support option files (--defaults-file, --defaults-extra-file, --defaults-group-suffix, --no-defaults)

In short, if the plan is to replace mysql with mysqlsh, put the thing in the open, and please make sure it can do what users can reasonably expect.

UPDATE: MySQL Cluster 7.5 inside and out

$
0
0
Publishing a book internationally turned out to be a bit more complex than I
originally thought. Therefore there are three different ways to order the book
MySQL Cluster 7.5 inside and out.

The E-book which is now available world-wide.
The paperback version. This is also now available world-wide.
Finally the bound version which is available from Nordic countries
and Germany and Switzerland.

The original idea was to publish it as an E-book and as a bound book.
Given that the book is 640 pages long I felt that I wanted a bound book
to ensure that I can read the book a lot. I've got a few copies of the bound
book at home and I have it on my desk all the time together with Jesper
and Mikiyas Pro MySQL NDB Cluster book.

As it turned out the printer only had international agreements to
print paperback books with figures in black and white (the bound
version have color figures). To ensure that the book is world-wide
available I decided to also publish a paperback version.

So for example at the UK/US Amazon's bookshop the versions available are
the E-book and the paperback version.

Personally I still prefer the bound version. I discovered that a german
internet site have international delivery. So if you want to buy the bound version
of the book you can use this site: Hugendubel.de.

If you have any comments on the book, any errata, you can publish a comment
on this blog. I will also publish comments to this blog every now and then when
I discover any errors or comments.

Feel free to also provide ideas for future inclusion in possible future editions of
this book.

Percona Monitoring and Management 1.8.0 Is Now Available

$
0
0
Percona Monitoring and Management

The latest release of Percona Monitoring and Management (PMM) 1.8.0 is available as of February 27, 2018.

Percona Monitoring and Management is a free and open-source platform for managing and monitoring MySQL and MongoDB performance. You can run PMM in your own environment for maximum security and reliability. It provides thorough time-based analysis for MySQL and MongoDB servers to ensure that your data works as efficiently as possible.

This release introduces many improvements in the user interface and optimizations of performance.

New landing page

The home page has been removed in favor of the Home dashboard to make the look and feel of PMM web interface more consistent. The Home dashboard gives a general overview of your system and provides links to useful resources. You can immediately go to a dashboard of your choice either by using the conventional Dashboard drop down at the top of the page or the new dashboard menu.

Improved dashboard menu layout

The new dashboard menu provides a convenient grouping of dashboards making the switching between dashboards easy: select a group, such as MySQL or OS, and choose from a short list in the menu that opens. The new dashboard menu is available from every dashboard in PMM.

Memory improvements

This release also features improved memory usage on the host system in PMM Server.  By default PMM now automatically scales its use with system size rather than using static amount of memory, unless you explicitly set the maximum value (by using the METRICS_MEMORY option in Docker, for example).

New Features

  • PMM-1145Move Percona Dashboards to Grafana Plugin
    We have updated the Percona Dashboards to use the Grafana Plugins system in order to simplify upgrades.
  • PMM-1470Implement a Custom Prometheus rds_exporter to Collect Amazon CloudWatch Metrics 
    You can now explore CloudWatch metrics from Prometheus, for example using the Advanced Data Exploration dashboard.  In prior versions we were using CloudWatch API calls directly.
  • PMM-2046Configure Memory Consumption Automatically for PMM Server
    In this release we improved memory usage in PMM Server.  By default PMM now automatically scales its use with system size rather than using static amount of memory.  You can override this behaviour, for example if you need to share resources with other containers by using the METRICS_MEMORY option in Docker.  You can use the old static size of memory by running:

    docker ... -e METRICS_MEMORY=786432

Improvements

  • PMM-1425Replace the Home Page with the Home Dashboard
    The home page has been removed in favor of the Home dashboard to make the look and feel of PMM web interface more consistent. The Home dashboard gives a general overview of your system and provides links to useful resources. You can immediately go to a dashboard of your choice either by using the conventional Dashboard drop down at the top of the page or the new dashboard menu.
  • PMM-1738Add a Dashboard Menu and Make the Discovery of Dashboards Easier
  • PMM-1976Apply Consistent Rules for Computing CPU Metrics 
    We updated the query that generates CPU utilization for the MySQL Overview, Summary and System Overview Dashboards as before we were being in-consistent in our determination of CPU.
  • PMM-2007Squash New Docker Layers for Smaller Total Size 
    We reduced the size of the Docker container from ~475 MB to ~350 MB
  • PMM-1711Add SQL and External Locks graphs to MySQL Performance Schema dashboard 
    Added new graph to the PERFORMANCE SCHEMA dashboard to show locks from perspective of count of events and from time.
  • PMM-1763Update the Forked Prometheus Exporter mysqld_exporter to the Latest Upstream Version to Include Recent Bug Fixes 
    The mysqld_exporter has been updated to the latest upstream prometheus/mysqld_exporter to include recent bug fixes.
  • PMM-2004Add /ping alias to nginx 
    Added basic health check URL to the API for PMM Server.
  • PMM-1365Provide Descriptions of All Metrics in the Cross Server Graphs Dashboard 
    We have added metric descriptions in order to improve understanding of the displayed metric series and to provide links to documentation/blog articles, beginning with the Cross Server Dashboard. 
  • PMM-1343Provide Descriptions of All Metrics in the Summary Dashboard 
  • PMM-1364Provide Descriptions of All Metrics in the MySQL InnoDB Metrics Dashboard 
  • PMM-1994Provide Descriptions of All Metrics in the MySQL Amazon Aurora Dashboard 
  • PMM-1922PMM-server as instance for all components on Server 
  • PMM-2005Upgrade Orchestrator to the Latest Stable Release 
  • PMM-1957Build Go 1.9.4 
    Updated Go to 1.9.4 which resolves a security problem in the go get command (For more information, see Golang issue #23672)

Bug Fixes

  • PMM-2124The Number of the New Version Is Missing in the Notification of the Successful Update of PMM 
  • PMM-1453MySQLD Exporter wrong mapping of innodb_buffer_pool_pages 
  • PMM-2029Deadlock when adding external exporter 
  • PMM-1908RDS MySQL nodes do not display Current QPS 
  • PMM-2100rds_exporter Crashed after Running for Several Minutes 
  • PMM-1511PXC Cluster Is Not Recognized Correctly When MariaDB Nodes Are Monitored 
  • PMM-1715MongoDB QAN: Wrong Per Query Stats: 
  • PMM-1893In QAN, the Tables Element Can Be Empty 
  • PMM-1941Fingerprint storage bug 
  • PMM-1933If some parts of collector got error, whole collector is down 
  • PMM-1934mysqld_exporter/collector/info_schema_auto_increment.go fails if there are same table names but with different cases 
  • PMM-1951Regression in pmm-admin add mysql:queries only – not working 

 

Analyze Your Raw MySQL Query Logs with ClickHouse

$
0
0

In this blog post, I’ll look at how you can analyze raw MySQL query logs with ClickHouse.

For typical query performance analyses, we have an excellent tool in Percona Monitoring and Management. You may want to go deeper, though. You might be longing for the ability to query raw MySQL “slow” query logs with SQL.

There are a number of tools to load the MySQL slow query logs to a variety of data stores. For example, you can find posts showing how to do it with LogStash. While very flexible, these solutions always look too complicated and limited in functionality to me.   

By far the best solution to parse and load MySQL slow query logs (among multiple log types supported) is Charity Majors Honeytail. It is great self-contained tool written in Go that has excellent documentation and is very easy to get started with. The only catch is it is only designed to work with SaaS log monitoring platform HoneyComb.io.  

My friends at Altinity replaced Honeytail’s interface that writes logs to HoneyComb with one that writes data to ClickHouse – giving us Clicktail! Clicktail retains most of Honeytail’s features, including support for MySQL slow query logs, yet uses ClickHouse instead of HoneyComb.io as a backend store.

Clicktail extracts all fields available in Percona Server for MySQL’s slow query log as you can see in Schema, and it takes just few configuration file options to get going.

Once we have Clicktail setup, we’ll have slow query log data flowing to ClickHouse basically in real time (and we can query it):

Raw MySQL Query Logs with ClickHouse

This query computes query avg latency and 99 percentile latency for queries with given fingerprints as well as the load this query pattern generates.

It is amazing to see how Clickhouse – which I’m running here on a single small Intel NUC computer – can run this query processing at almost 100 million of rows/sec:

Raw MySQL Query Logs with ClickHouse 2

This query shows us how many distinct InnoDB pages different queries touched during last day. We can also easily find the slowest query in our log:

Raw MySQL Query Logs with ClickHouse 3

The ability to query both specific queries as presented in the log file, as well as their normalized versions, is very powerful.

You may also notice in this case that ClickHouse is not particularly fast. We would have better performance in traditional MySQL if we indexed the query_time column. This is a trade-off of index-less column-store design. While it allows for very fast parallel scans, it does not allow us to use indexes.

You may also notice query #2 used a range on column _time and ended up scanning fewer rows than other queries. While ClickHouse does not use indexes, it does allow you to define a sort key (one per table) that can be pretty much used as a traditional index for range queries.

If you ever need to do some advanced digging in raw MySQL slow query logs, consider doing it with ClickHouse and Clicktail!

Webinar Thursday March 1, 2018: Performance Schema for MySQL Troubleshooting

$
0
0
Performance Schema for MySQL Troubleshooting

Performance Schema for MySQL TroubleshootingPlease join Percona’s Principal Support Engineer, Sveta Smirnova, as she presents Performance Schema for MySQL Troubleshooting on Thursday, March 1, 2018, at 10:00 am PST (UTC-8) / 1:00 pm EST (UTC-5).

Performance Schema, first introduced in version 5.5, is a really powerful tool. It is actively under development, and each new version provides even more instruments for database administrators.

Performance Schema is complicated. It is also not free: it can slow down performance if you enable certain instruments.

In this webinar I will discuss:

  • How to get started with Performance Schema
  • How to effectively set it up, specifically for your troubleshooting case
  • When and how data gets collected
  • Which instruments affect performance and why
  • What you can instrument with Performance Schema
  • Where to find more information
  • How sys schema can help you to more effectively work with Performance Schema

Register for the webinar now.

MySQL TroubleshootingSveta Smirnova, Principal Technical Services Engineer

Sveta joined Percona in 2015. Her main professional interests are problem-solving, working with tricky issues, bugs, finding patterns which can solve typical issues quicker, teaching others how to deal with MySQL issues, bugs and gotchas effectively. Before joining Percona Sveta worked as Support Engineer in MySQL Bugs Analysis Support Group in MySQL AB-Sun-Oracle. She is the author of the book “MySQL Troubleshooting” and JSON UDF functions for MySQL.

Using MySQL 8.0: what to expect

$
0
0
Mysql8

MySQL 8.0 will be GA soon (just my assumption: Oracle doesn't tell me anything about its release plans) and it's time to think about having a look at it.
If this is your first try of MySQL 8, get prepared for several impacting differences from previous versions.

In this article I won't tell you what you can do with MySQL 8: there is plenty of material about this, including in this very blog. I will instead concentrate on differences from previous versions that users need to know if they want to avoid surprises.

Data Directory

Let's start with an observation of the data directory.
After a standard installation, without any additional options, I see the following:

Files that I expected to see

auto.cnf
ib_buffer_pool
ib_logfile0
ib_logfile1
ibdata1
ibtmp1
(dir) mysql
(dir) performance_schema
(dir) sys

These files are also present in 5.7.

Files that are new in 8.0

binlog.000001
binlog.index

log-bin is ON by default. You need to remember this if you are using a MySQL server for a benchmark test that used to run without binary logs.

ca-key.pem
ca.pem
client-cert.pem
client-key.pem
private_key.pem
public_key.pem
server-cert.pem
server-key.pem

Now the MySQL generates all the certificates needed to run connections securely. This will greatly simplify your task when setting up a new instance.

mysql.ibd

This was completely unexpected! The mysql database has now its own tablespace. This is probably due to the new Data Dictionary, which is implemented in InnoDB. You will notice that all the InnoDB tables in MySQL use this tablespace, not only dictionary tables. This will help keeping administrative data separate from operational data in the rest of the server.

undo_001
undo_002

The undo logs have now their own tablespace by default.

Global variables

There are a lot of changes in global variables. Here's the list of what will impact your work when you use MySQL 8.0 for the first time:

character_set_client        utf8mb4
character_set_connection utf8mb4
character_set_database utf8mb4
character_set_results utf8mb4
character_set_server utf8mb4

All character sets are now utf8mb4. In MySQL 5.7, the default values are a mix of utf8 and latin1.

default_authentication_plugin   caching_sha2_password

This is huge. Using this plugin, passwords are stored in a different way, which guarantees more security, but will probably break several workflows among the users. The bad thing about this change implementation is that this password format contains characters that don't display well on screen, and you can see garbled output when inspecting the "user" table.

local_infile    OFF

Loading local files is now prevented by default. If you have a workflow that requires such operations, you need to enable it.

log_bin ON
log_slave_updates ON

We've seen from an inspection of the local directory that binary logging is enabled by default. But also very important is that log_slave_update is enabled. This is important to have slaves ready to replace a master, but will severely affect performance in those scenarios where some slaves were supposed to run without that feature.

master_info_repository  TABLE
relay_log_info_repository TABLE

Also impacting performance is the setting for replication repositories, which are now on TABLE by default. This is something that should have happened already in MySQL 5.6 and was long overdue.

Surprisingly, something that DOES NOT get enabled by default is Global Transaction Identifiers (GTID). This is also a legacy from decisions taken in MySQL 5.6. Due to the GTID implementation, enabling them by default is not possible when upgrading from a previous version. With new data in a fresh installation, it is safe to enable GTID from the start.


Users


There are two new users when the server is created:

mysql.infoschema
mysql.session

Theoretically, mysql.session also exists in 5.7, but it was introduced long after GA, so it still qualifies as a novelty.

Then, when the server starts, you get a grand total of 4 users (root and mysql.sys are inherited from MySQL 5.7.)


Mixed oddities


When MySQL initializes, i.e. when the server starts for the first time and creates the database, you will notice some slowness, compared to previous versions. This is in part due to the data dictionary, which needs to create and fill 30 tables, but it is not a big deal in terms of performance. In some systems, though, the slowness is so acute that you start worrying about the server being stuck.

I noticed this problem in my Intel NUC running with SSD storage. In this box, the initialization time took a serious hit:

Version time
5.0.96 1.231s
5.1.72 1.346s
5.5.52 2.441s
5.6.39 5.540s
5.7.21 6.080s
8.0.3 7.826s
8.0.4 38.547s

There is no mistype. The initialization for 8.0.4 lasts 6 times more than 5.7.
This doesn't happen everywhere. On a Mac laptop running on SSD the same operation takes almost 9 seconds, while 5.7 deploys in less than 5. It is still a substantial difference, one that has totally disrupted my regular operations in the NUC. I investigated the matter, and I found the reason. In 8.0, we have a new (hidden) table in the data dictionary, called st_spatial_reference_systems. Up to MySQL 8.0.3, this table was filled using a single transaction containing roughly 5,000 REPLACE INTO statements. It is a lot of data, but it happens quickly. For comparison, in MySQL 8.0.3 the initialization is only 2 seconds slower than 5.7.
The reason for the slowness in 8.0.4 is that there was a new command added to the syntax: CREATE SPATIAL REFERENCE SYSTEM, which is now used 5,000 times to fill the table that was previously filled with a single transaction. I don't know why someone in the MySQL team thought that changing this operation that is hidden from users was a good idea. The data is contained in the server itself and it goes into a data dictionary table, also not visible to users. I am sure I can find at least two methods to load the data faster. I was told that this glitch will be fixed in the next release. I'm waiting.

Speaking of initialization, the mysql_install_db script has been removed for good in 8.0. If you are still using it instead of the recommended mysqld --initialize, you should adapt asap.

This list is far from being exhaustive. I recommend reading What's new in MySQL 8 before upgrading.
If you are impatient, dbdeployer can help you test MySQL 8 quickly and safely.



MySQL Security – Password Validation Plugin

$
0
0
When thinking about security within a MySQL installation, you should consider a wide range of possible procedures / best practices and how they affect the security of your MySQL server and related applications. MySQL provides many tools / features / plugins in order to protect your data including some advanced features like Transparent Data Encryption […]

MySQL 8.0 v/s MariaDB: Comparison of Database Roles

$
0
0

 

In our last blog, we had a look at MySQL 8 and mentioned new features available here. However, some of those features are already in MariaDB and have been for a while. We will here compare database roles in both server dialects.

The Purpose of Database Roles

It’s common for numerous users within an organization to share the same database privileges. A role bundles a number of privileges together so that the DBA can set the privileges for a group of users all at once, rather than having to set each user’s privileges individually.  

With shared applications, it is not uncommon for multiple users to share the same user account. The drawback to this arrangement is that there is no way to see which actual user was responsible for which action.

Roles make managing this much easier. For example, there could be a number of users assigned to an Interviewer role, with identical privileges.  Changing the privileges for all the Interviewers is a matter of simply changing the role’s privileges.  Meanwhile, the individual user is still linked with any actions that they perform within the database.

Fixed vs. Flexible Roles

There are two kinds of database roles: fixed and flexible.

Fixed roles are those which automatically exist in a database. Adding a user to one of these roles will not change that user’s permissions in any other database.

Any user or role can be added to a database role. Once a user has been added to a role, they may also be able to add other users or roles to that role, depending on the vendor.

Flexible database roles are those that you create yourself in the database. When you start with a new database, there are no flexible roles, just any defined fixed roles. The upside of this is that you are free to create all of the roles that you need and grant all of the permissions that you desire to these roles.

It’s very important to be careful when adding flexible roles to a fixed role as you could very easily elevate privileges for a large number of users in one fell swoop!

Roles in MariaDB

MariaDB does not come with fixed roles, but has supported flexible user roles since version 10.0.5.  They were implemented almost exactly as specified in the SQL Standard 2003, features T331 “Basic roles” and T332 “Extended Roles”, so that role management follows a similar process as with many other popular DBMSes:

  • Roles are created with the CREATE ROLE statement and dropped with the DROP ROLE statement.
  • Roles are then assigned to a user with an extension to the GRANT statement, while privileges are assigned to a role in the regular way with GRANT. Similarly, the REVOKE statement can be used to both revoke a role from a user or to revoke a privilege from a role.
  • Once a user has connected, he/she can obtain all privileges associated with a role by setting a role with the SET ROLE statement. The CURRENT_ROLE() function returns the currently set role for the session if any.
  • Only roles granted directly to a user can be set, roles granted to other roles cannot. Instead, the privileges granted to a role, which is, in turn, granted to another role (grantee), will be immediately available to any user who sets this second grantee role.

Examples

Creating a role and granting a privilege:

CREATE ROLE interviewer;

GRANT SHOW DATABASES ON *.* TO interviewer;

GRANT interviewer to tom_m;

Note, that tom_m has no SHOW DATABASES privilege, even though he was granted the interviewer role.  He needs to set the role first:

SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
+--------------------+

SELECT CURRENT_ROLE;
+--------------+
| CURRENT_ROLE |
+--------------+
| NULL         |
+--------------+

SET ROLE interviewer;

SELECT CURRENT_ROLE;
+--------------+
| CURRENT_ROLE |
+--------------+
| interviewer  |
+--------------+

SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| ...                |
| information_schema |
| mysql              |
| performance_schema |
| test               |
| ...                |
+--------------------+

-- removes all roles
SET ROLE NONE;

Roles can also be granted to roles:

CREATE ROLE trainer;

GRANT SELECT ON data.* TO trainer;

GRANT trainer TO interviewer;

But one does not need to set a role granted to a role. For example, tom_m will automatically inherit all trainer privileges when he sets the interviewer role:

SELECT CURRENT_ROLE;
+--------------+
| CURRENT_ROLE |
+--------------+
| NULL         |
+--------------+

SHOW TABLES FROM data;
Empty set (0.01 sec)

SET ROLE interviewer;

SELECT CURRENT_ROLE;
+--------------+
| CURRENT_ROLE |
+--------------+
| interviewer  |
+--------------+

SHOW TABLES FROM data;
+------------------------------+
| Tables_in_data               |
+------------------------------+
| set1                         |
| ...                          |
+------------------------------+

Default Roles

The original MariaDB roles implementation specified that one had to explicitly set a role using the SET ROLE statement. This was not always convenient and sometimes not even possible, such as in the case of accounts used by applications.
To solve this issue MariaDB introduced the concept of a default role. A default role for given user is automatically enabled when a user connects.
To set a default role you use the SET DEFAULT ROLE command:

SET DEFAULT ROLE interviewer;

This stores your default role in the mysq.user table, and next time you connect the interviewer role will be enabled for you automatically.

You can also set a default role for another user:

SET DEFAULT ROLE interviewer FOR user@host;

Similar to the standard SET ROLE statement, you can remove a default role at any time using:

SET DEFAULT ROLE NONE;

Roles in MySQL

MySQL before 8.0 did not support roles. However, Oracle has for some years implemented “sort-of roles support” in their GUI client MySQL Workbench.  It defines a number of Fixed roles available from within Workbench (and no other clients obviously, as it is not implemented server-side).

MySQL now supports flexible roles, which can be created and dropped, as well as have privileges granted to and revoked from them.  Moreover, roles can be granted to and revoked from individual user accounts. The active applicable roles for an account can be selected from among those granted to the account, and can be changed during sessions for that account.

Creating Roles and Granting Privileges to Them

Consider the scenario where an application uses a database named app_db.  Associated with the application, there can be accounts:

  • for developers who create and maintain the application, and
  • for users who interact with it.

There are usually three types of access needed:

  • Developers need full access to the database.
  • Some users need only read access,
  • while others need read/write access.

To avoid having to grant privileges individually to many user accounts, we can create roles as names for the required sets of privileges. This makes it easy to grant the required privileges to different user accounts, by granting the appropriate roles.

Roles can be created using the CREATE ROLE command:

CREATE ROLE 'app_developer', 'app_read', 'app_write';

Role names are much like user account names and consist of a user part and host part in 'user_name'@'host_name' format. The host part, if omitted, defaults to “%”. The user and host parts can be unquoted unless they contain special characters such as “” or “%”.

To assign privileges to the roles, we would execute the GRANT statement using the same syntax as for assigning privileges to user accounts:

GRANT ALL ON app_db.* TO 'app_developer';

GRANT SELECT ON app_db.* TO 'app_read';

GRANT INSERT, UPDATE, DELETE ON app_db.* TO 'app_write';

Here is how we would create one developer account, two read-only accounts, and one read/write account using CREATE USER:

CREATE USER 'dev_acc_1'@'localhost' IDENTIFIED BY 'dev_acc_1_pw';

CREATE USER 'read_acc_1'@'localhost' IDENTIFIED BY 'read_acc_1_pw';

CREATE USER 'read_acc_2'@'localhost' IDENTIFIED BY 'read_acc_2_pw';

CREATE USER 'rw_acc_1'@'localhost' IDENTIFIED BY 'rw_acc_1_pw';

We could assign each user account its required privileges using GRANT statements as we did earlier, but that would require enumerating individual privileges for each user.  It’s more efficient to use an alternative GRANT syntax that permits granting roles rather than privileges:

GRANT 'app_developer' TO 'dev_acc_1'@'localhost';

GRANT 'app_read' TO 'read_acc_1'@'localhost', 'read_acc_2'@'localhost';

GRANT 'app_read', 'app_write' TO 'rw_acc_1'@'localhost';

Mandatory Roles

In the 8.0.2 dev release, the MySQL team introduced the mandatory roles extension, making it possible to specify roles as mandatory by naming them in the value of the mandatory_roles system variable. A mandatory role is granted to all users, so that it need not be granted explicitly to any account.

Mandatory roles may be set either at server startup or at runtime. This variable can be set with a list of roles:

  • To specify mandatory roles at server startup, define mandatory_roles in your server my.cnf file:
[mysqld]

mandatory_roles='role1,role2@localhost,r3@%.acme.com'
  •  To set and persist mandatory_roles at runtime, use a statement such as this:
SET PERSIST mandatory_roles = 'role1,role2@localhost,r3@%.acme.com'

Once set, the roles in the list will be added to the privileges of all users, including future ones.

Here’s an example of how this feature could be utilized:

CREATE ROLE post_reader;

GRANT SELECT ON company.* TO post_reader;

SET PERSIST mandatory_roles = post_reader;

The above statements set the post_reader role as a mandatory role at runtime.

Distinguishing between Roles and Regular Users in the mysql.user Table

As reported by Peter Laursen on the MySQL site:

When a role is created, a row is added to the mysql.user table.  But the row is not clearly distinguishable from a row describing a plain user.

The only difference I see is the value of the account_locked column.  It is “Y” for the View and “N” for the Table. I don’t know if this can reliably be used for distinguishing roles and plain users. I don’t find any help in documentation.

Being unable to distinguish between roles and plain users does not just affect DBAs; it also confuses the database server!

CREATE role someone;

CREATE USER someone; -- Error Code: 1396: Operation CREATE USER failed for 'someone'@'%'

DROP USER someone; -- success. Erhh??? The role was dropped as shown by

SELECT COUNT(*) FROM mysql.user WHERE `host` = '%'; -- returns "0"

Laursen suggests the following two fixes:

Either

  1. don’t add roles to mysql.user but to a new table named mysql.role,
  2. add a new column to mysql.user named `ìs_role`. (Also possible with MariaDB)

Conclusion

With the release of version 8, MySQL has made great strides in closing the gap in user roles support as specified in the SQL Standard 2003 and implemented in popular DBMSes such as MariaDB. In future blogs, we’ll perform similar comparisons with respect to Window Functions and Common Table Expressions.

The post MySQL 8.0 v/s MariaDB: Comparison of Database Roles appeared first on SQLyog Blog.

How To Buy Software 2018

$
0
0

Buying software solutions for your company is a skill just like any other business practice. To be effective at purchasing it is necessary to have a clear understanding of what you require and a plan on how to evaluate potential vendors. When time is also a factor a working knowledge of the internal buying processes and expectations of your employer are also important.

The wide variety of similar sounding products with hard to distinguish feature differentiators can be daunting. In order to get the right software at a competitive price within the desired timeframe there are 4 important things to consider.

Here’s the short list:

  • Define requirements by focusing on needs instead of features
  • Prepare your budget, know your buying process
  • Check provider quality and support
  • Make the most of your trial period

 

And here’s the longer one:

Understand Your Needs

Effective software purchasing starts with clearly defining your key needs. What are you trying to accomplish by acquiring the software and why? What event is driving you to make this acquisition and when are you hoping to have a solution in place?

Having answers to these questions will help focus your search and make it easier for vendors to understand if they are a match for your requirements. Many products have superficial similarities but take different approaches to solving a problem. Being clear and direct about your use case means a vendor can do a better job of explaining the exact way they can be of benefit. You will get better feedback to use in comparing competitors.

While it is beneficial to take time detailing the key requirements that your software must provide to meet your business goals, focusing narrowly on specific features can be counterproductive. Narrowing your focus to these needs will limit your evaluation to solutions that keep you  distracted with impressive looking side-features that sound nicer than they perform. Focus on the problem first and let a vendor show you how they have created a solution for it.

Finally don’t get distracted by secondary features or product roadmaps. While additional features might be nice they are never as important as making sure your core requirements are met. Future upgrades can also be tempting but buying software based on future promises often leads to disappointment.

Establish an Informed Budget

Value is relative; this is never more true than when buying software. If you have no burning problem to solve then the temptation may be to go with a very cheap or “free” open source solution. The reality is that no software is ever free; there are always costs involved in maintaining and using it. The most important consideration is how effective the software will be in solving or preventing your core problem. Is this software mission critical? Consider the costs you incur if an issue goes undiscovered or remains unfixable for a period of time; that should set a baseline for what you budget for a solution. Software can also have an impact on your bottom line by allowing you to use resources more efficiently and saving you money on hardware or services.

It is important to consider how your organization buys software before you begin your search. What are the budget limits? Who can grant approval at different levels of budget spend? Are there other parts of the organization who should be brought into an evaluation in order to increase the budget pool? Other procedural considerations like the need for NDA’s, security reviews or the involvement of a procurement team can call impact the timeline to acquire software. The more you know about your internal processes the better a vendor can work with you to make sure your project is delivered on time and within budget.

Ensure the Software is Well Supported

When looking at a piece of software that’s new to you, it’s a smart idea to look into the company who developed it.

Do they have a good reputation? Have they been in business long? Do they keep their products updated and well supported? These are all things you should investigate to be certain that the software you pick will perform capably, and if you run into trouble when using it you’ll be able to access the help you need.

Reading through customer reviews is a great way to get an impression of a company’s credibility and the quality of software they provide. If the vendor offers free support during a trial process, try it out. Ping the support team with a question about product usage or any feature ideas you have. If they are truly interested in being a good partner to their customers you will find that they offer a high level of support at all stages of the buying process.

VividCortex offers support for usage questions as well as technical issues. Our goal is to deliver an answer during business hours within 5 minutes of any question being asked email or Intercom chat built into the product. We also offer a premium tier license that includes 24/7 support at that same great level of attention.

Trial the Software Before Purchase

Many software vendors offer free trials for customers to see the performance of their product for themselves. These are excellent opportunities to test drive the software you’re considering before making any commitments.

Once you find a piece of software that appeals to you ask for a free a trial and try it in your environment. That way you’ll be able to rest assured that the software meets your business needs, functions properly and integrates well with your systems—or you’ll discover any issues before it becomes too late.

A common mistake is going into a trial unprepared or without sufficient time allocated to do a meaningful evaluation. Make a plan as to what team members will be involved in the evaluation and what everyone’s tasks and goals are. Don’t wait until the last day of the trial to login and review data; you will waste a great opportunity to gain more insight about a product you may purchase as well as insight about your own problems.

VividCortex does offers a free trial; the signup page can be found here: https://app.vividcortex.com/sign-up

 

In Conclusion

Purchasing the right software is critical to the health of a technology based organization. The right approach matters and preparation counts. The best way to ensure you get what you need at a price you can afford is to be open and honest about your priorities and budget.

If the solution you pick fails to meet expectation, then working with lackluster tools will become irritating fast. Even worse, switching software solutions once your business gets going is a costly and painful process that’s made harder by the knowledge it all could have been easily avoided in the first place.

Conducting strong research is the best defense against these problems, so be thorough when following the advice above, consider all your options carefully, and you’ll be sure to end up with software that’s perfect for you.

 

Great Metrics Graphs: Percona Monitoring and Management vs. gnuplot

$
0
0
Percona Monitoring and Management vs. gnuplot

In this blog post, we’ll checkout Percona Monitoring and Management vs. gnuplot when it comes to creating great metrics graphs. gnuplot is great, but PMM might provide graphs that are easier to read.

Percona Monitoring and Management (PMM) is our free and open-source platform for managing and monitoring MySQL®, MariaDB® and MongoDB® performance, and is based on Grafana and Prometheus. It collects many kinds of metrics: OS metrics, MySQL metrics or MongoDB metrics. But there are times where you just ran a benchmark or collected your specific metrics and you want to visualize them.

For a long time, I used gnuplot for that (and I still like it). But when I was working on a recent blog post, one of my colleagues wrote me:

AHHHHHHH! My eyes are bleeding from those graphs!!

(Guess what, he is working on PMM. 😉 )

So I investigated how can I use PMM to plot my graphs from my collected metrics. Here’s a graph that I was able to generate showing a count of queries based on metrics collected from ProxySQL:

Just for comparison here is the graph I created with gnuplot:

Grafana’s MySQL data source plugin

Prometheus is the default data source in PMM. After some research and testing, I realized loading metrics into Prometheus from a file is just a nightmare! So what can I do?

Luckily, Grafana supports multiple data sources, including MySQL. That’s great news. You can use this functionality to point your PMM server Grafana data source to the MySQL server that contains the data you’d like to plot.

On PMM you can go to “Data Sources” menu and add the MySQL server:

Choose the “type” MySQL and add your MySQL credentials. That’s all! At this point, PMM creates a graph from your “my_metrics” database.

Loading the metrics

I assume you have your metrics in a file (my metrics are in a CSV file). I am going to use “Load data local infile”. First I create a table:

CREATE TABLE `my_metrics_table` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `digest` varchar(20) DEFAULT NULL,
  `count` int(11) unsigned DEFAULT NULL,
  `avg_time` int(11) unsigned DEFAULT NULL,
  `query` varchar(200) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_time` (`time`)
) ENGINE=InnoDB AUTO_INCREMENT=512 DEFAULT CHARSET=latin1

As we can see, just a normal MySQL table. Let’s load the data:

LOAD DATA LOCAL INFILE "/var/lib/mysql-files/metrics_import.csv"
INTO TABLE my_metrics_table
COLUMNS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '"'
ESCAPED BY '"'
LINES TERMINATED BY 'n'
IGNORE 1 LINES
(time,digest,count,avg_time,query);

No magic here either, just loading in the rows into the table. The result is:

mysql> select * from my_metrics_table limit 10;
+----+---------------------+--------------------+-------+----------+----------------------------------+
| id | time                | digest             | count | avg_time | query                            |
+----+---------------------+--------------------+-------+----------+----------------------------------+
|  1 | 2018-02-26 08:43:32 | 0x80F0AE01FE6EFF1B |     3 |   443220 | UPDATE sbtest1 SET c=? WHERE k=? |
|  2 | 2018-02-26 08:43:33 | 0x80F0AE01FE6EFF1B |     5 |   481545 | UPDATE sbtest1 SET c=? WHERE k=? |
|  3 | 2018-02-26 08:43:34 | 0x80F0AE01FE6EFF1B |     7 |   711151 | UPDATE sbtest1 SET c=? WHERE k=? |
|  4 | 2018-02-26 08:43:35 | 0x80F0AE01FE6EFF1B |    10 |   745683 | UPDATE sbtest1 SET c=? WHERE k=? |
|  5 | 2018-02-26 08:43:36 | 0x80F0AE01FE6EFF1B |    13 |   696490 | UPDATE sbtest1 SET c=? WHERE k=? |
|  6 | 2018-02-26 08:43:37 | 0x80F0AE01FE6EFF1B |    17 |   657790 | UPDATE sbtest1 SET c=? WHERE k=? |
|  7 | 2018-02-26 08:43:38 | 0x80F0AE01FE6EFF1B |    21 |   635473 | UPDATE sbtest1 SET c=? WHERE k=? |
|  8 | 2018-02-26 08:43:39 | 0x80F0AE01FE6EFF1B |    24 |   638480 | UPDATE sbtest1 SET c=? WHERE k=? |
|  9 | 2018-02-26 08:43:40 | 0x80F0AE01FE6EFF1B |    26 |   661415 | UPDATE sbtest1 SET c=? WHERE k=? |
| 10 | 2018-02-26 08:43:41 | 0x80F0AE01FE6EFF1B |    30 |   644853 | UPDATE sbtest1 SET c=? WHERE k=? |
+----+---------------------+--------------------+-------+----------+----------------------------------+

Creating the graphs

Just with simple MySQL queries, here is an example:

SELECT
UNIX_TIMESTAMP(time) as time_sec,
`avg_time` as value,
concat(digest,' - ', query) as metric
FROM my_metrics_table
WHERE $__timeFilter(time)
ORDER BY time ASC

With this query, we are going to graph the “avg_time”, which is the average execution time of my queries. But what is “$__timeFilter”? There are some default macros, let me copy-paste the manual here:

Time series:
- return column named time_sec (UTC in seconds), use UNIX_TIMESTAMP(column)
- return column named value for the time point value
- return column named metric to represent the series name
Table:
- return any set of columns
Macros:
- $__time(column) -> UNIX_TIMESTAMP(column) as time_sec
- $__timeFilter(column) ->  UNIX_TIMESTAMP(time_date_time) ≥ 1492750877 AND UNIX_TIMESTAMP(time_date_time) ≤ 1492750877
- $__unixEpochFilter(column) ->  time_unix_epoch > 1492750877 AND time_unix_epoch < 1492750877
- $__timeGroup(column,'5m') -> (extract(epoch from "dateColumn")/extract(epoch from '5m'::interval))::int
Or build your own conditionals using these macros which just return the values:
- $__timeFrom() ->  FROM_UNIXTIME(1492750877)
- $__timeTo() ->  FROM_UNIXTIME(1492750877)
- $__unixEpochFrom() ->  1492750877
- $__unixEpochTo() ->  1492750877

And the result is:

Nice, we created a graph based on a MySQL table. That means if you have almost any kind of metrics or benchmark you can easily create some graphs and analyze them.

Of course, MySQL is not a time series database. With hundred millions of records, it is not going to work, or it will be quite slow. It also does not have features like Prometheus where we can easily use “rate” and “irate”.  If you require metrics series analysis across large datasets, consider ClickHouse.

Rate in MySQL

On my next graph I wanted to show the QPS, but in my table the number of QPS is a counter that’s increasing. I only needed the differences. How can I do that without “rate”? We can do some MySQL magic as well and write a query like this:

select
      UNIX_TIMESTAMP(mt.time) as time_sec,
      if( @lastDigest = mt.digest, mt.count - @lastCount, 0 ) as value,
      concat(digest,' - ', query) as metric,
      @lastDigest := mt.digest,
      @lastCount := mt.count
   from
      my_metrics_table mt,
      ( select @lastDigest := 0,
               @lastCount := 0 ) SQLVars
     WHERE $__timeFilter(mt.time)
    ORDER BY mt.time ASC;

This query is going to calculate the differences between the last and the current value, which is what I need. The result is:

Another nice graph what you can show to your boss. 😉

Conclusion

PMM is based on open-source tools and you can modify any parts of it. Just like in this example, I could not use Prometheus (it would have been much more complicated) so I used a MySQL data source. I could have chosen InfluxDB as well, but I already had MySQL so I did not have to install anything at all.

Hopefully, this is going to help you to make some nice graphs for your benchmarks.

I still like gnuplot as well. 😉

Replication handler error HA_ERR_KEY_NOT_FOUND and Memory Tables In Replication.

$
0
0

 Last_SQL_Error: Could not execute <Update/insert/delete>_rows event on table <dbname>.<tablename>; Can’t find record in ‘<tablename>’, Error_code: 1032; handler error HA_ERR_END_OF_FILE; the event’s master log <master binary log file name>, end_log_pos <master log file position>

This is one of the error for MySQL Replication when MASTER and SLAVE replica not in sync. The Reason for replication getting out of sync due to various reasons. But the common cause is particular table row or data not matched/missing on the slave while applying transaction received from MASTER. This transaction can be insert/update/delete type.

In this blog post will discuss support for MEMORY storage engine table with MySQL Replication and few examples with a possible solution. As per official MySQL DOC,  support for replication with memory storage engine is “LIMITED”.

The reason is limited because of the MEMORY storage engine functionality, which stores all data in memory other than table metadata and structure. And this data will get flushed from the memory at the time of MySQL server restart.

mem_rpl

Above diagram illustrating stages before and after mysqld service restart on the slave.

Possible Solutions to bring backup replication in sync: [ Without downtime]

Option 1: Set slave_exec_mode to IDEMPOTENT It will suppress duplicate-key and no-key-found errors. Default slave_exec_mode is STRICT  means no such suppression takes place.

Option 2: Skip memory tables from replication using replication filter “replicate_ignore_table”. From 5.7.3 we can set replication filters dynamically without mysql service restart.

Option 3: If you want to keep data persistently then better to covert this table from MEMORY to InnoDB storage engine type using ALTER TABLE… ENGINE=Innodb command.

Selecting one of the options is depending on what we really need. For example, rather than skipping transaction one by one we can set Set slave_exec_mode to IDEMPOTENT  for the time being to get replication in sync and after that set it back to STRICT again.

All set !!

New Defaults in MySQL 8.0

$
0
0

MySQL 8.0 comes with improved defaults, aiming at the best out of the box experience possible. Here we describe the changes and why they are made.

Introduction

Generally speaking, a good default is “the best choice for most users, most of the time”.…

Announcement: p99 Percentile Metrics

$
0
0

I’m pleased to announce that VividCortex now offers 99th percentile metrics to help understand latency outliers in a query workload. These metrics provide visibility beyond the average latency, help identify the worst outliers, and improve focus on the customer experience. They are offered for all of the databases we currently support when using On-Host monitoring.

What You'll See

Latency percentile metrics are one of our most popular feature requests, so we know this will make a lot of you very happy! We actually started collecting these metrics some time ago; you’ll have p99 latency metrics for the last couple of months if you look back at your historical metrics. These metrics are captured globally for an environment, per-query, per-database, per-user, per-verb, per-caller and per-custom-query-tag.

Why Did We Choose to Implement This? 

It is extremely useful for a lot of reasons. Averages can be misleading. Customers don’t just experience an application’s average behavior; they remember the worst experience they’ve had. P99 metrics show outlying behavior in the long-tail, while averages don’t. You can rank by highest-latency p99 in the Profiler which makes it very easy to focus on the queries with the worst outliers.

They’re most meaningful for high-frequency queries; where other monitoring systems have trouble providing any visibility at all into fast and frequent queries, we can also identify outlier performance. This is a huge blind spot for many people.

It is also a useful feature for proactive monitoring and notification. Since we are generating this value per-query you can set an alert on specific query performance. This could be a much more accurate way of alerting on unusual behaviour as compared to setting a threshold against average latency.

What Exactly Are We Collecting? 

There is a wide variety in what monitoring tools delivers as a “percentile” measurement. The most literal definition is to take a complete population of datasets, discard a certain percentage of them such as the top 1%, and then present the largest remaining value. What VividCortex is returning for p99 is a metric of percentiles. We don’t keep the full dataset from which a percentile can be calculated; our agents calculate the p99 at 1 second intervals with an approximation algorithm and store a time series metric of that value. This is similar to how StatsD generates their upper_99 metrics of percentiles.

When charting the metric over an arbitrary timeframes, the API averages the metrics for display. This is necessary whenever you request data at a time resolution that differs from the stored resolution. If you want to render a chart of a metric over a day at 600px wide, each pixel will represent 144 seconds of data. We also average the data when it is downsampled for long-term storage at a lower resolutions.

In Conclusion

It is interesting that averaging percentiles is improper, but still useful. If you store a p99 metric and then zoom out and view an averaged version over a long time range, it may be quite different from the actual 99th percentile. However the ways in which it is different don’t render it unusable for the desired purpose, i.e. understanding the worst experience most of your users are having with your application. Regardless of their exact values, percentile metrics tend to show outlying behavior and get bigger when outlying behavior gets badder. Super useful!

VividCortex does offer a free trial; the signup page can be found here: https://app.vividcortex.com/sign-up

 

 

Percona Toolkit 3.0.7 Is Now Available

$
0
0

Percona Server for MongoDBPercona announces the release of Percona Toolkit 3.0.7 on March 1, 2018.

Percona Toolkit is a collection of advanced open source command-line tools, developed and used by the Percona technical staff, that are engineered to perform a variety of MySQL®, MongoDB® and system tasks that are too difficult or complex to perform manually. With over 1,000,000 downloads, Percona Toolkit supports Percona Server for MySQL, MySQL, MariaDB®, Percona Server for MongoDB and MongoDB. Percona Toolkit, like all Percona software, is free and open source.

You can download packages from the website or install from official repositories.

This release includes the following changes:

New Features:

  • PT-633: Add the --mysql-only option to pt-stalk for RDS
    We’ve improved data collection from Amazon RDS MySQL and Amazon Aurora MySQL to only perform remote mysqld checks. Previously we would also collect from the local system which was confusing.

Bug fixes:

  • PT-244: The --data-dir option of pt-online-schema-change is broken for partitioned table.
  • PT-1256pt-table-sync does not use the character set for the table it is synchronizing
  • PT-1455pt-osc is stuck when filtering out on the slave the table that is being altered
  • PT-1485:  The Security section of pt-mysql-summary is broken in versions greater than 5.6
  • PMM-1905Explain fails if it encounters a negative ntoreturn

Known Issues:


Visualize This! MySQL Tools That Explain Queries

$
0
0
MySQL Tools

In this blog post, I want to go over some of the day-to-day MySQL tools and methods DBAs use to analyze queries and visualize “what is going on?” I won’t be going into the nitty-gritty details of each of these tools, I just want to introduce you to them and show you what they look like so you will know what types of information they provide.

This isn’t a comprehensive list by any means but consider it a primer for those starting with MySQL and wanting to know what a query is going to do or is doing.

The two sides of query analysis are examining a query BEFORE you run it, and then analyzing what actually happened AFTER you run it.

Let’s start with the tools you can use to predict a query’s future.

In the beginning, there was EXPLAIN. The venerable EXPLAIN command has been with us a long time as a built-in MySQL utility statement. Its purpose is to explain that what the optimizer predicts is the best “plan”, and describe that to us. It tells us where data is gathered from, how it is filtered, and how it is combined or aggregated and much more:

> EXPLAIN SELECT CONCAT(customer.last_name, ', ', customer.first_name) AS customer,     address.phone, film.title     FROM rental INNER JOIN customer ON rental.customer_id = customer.customer_id     INNER JOIN address ON customer.address_id = address.address_id     INNER JOIN inventory ON rental.inventory_id = inventory.inventory_id     INNER JOIN film ON inventory.film_id = film.film_id     WHERE rental.return_date IS NULL     AND rental_date + INTERVAL film.rental_duration DAY < CURRENT_DATE()     LIMIT 5G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: film
         type: ALL
possible_keys: PRIMARY
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 1000
        Extra: NULL
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: inventory
         type: ref
possible_keys: PRIMARY,idx_fk_film_id
          key: idx_fk_film_id
      key_len: 2
          ref: sakila.film.film_id
         rows: 1
        Extra: Using index
*************************** 3. row ***************************
           id: 1
  select_type: SIMPLE
        table: rental
         type: ref
possible_keys: idx_fk_inventory_id,idx_fk_customer_id
          key: idx_fk_inventory_id
      key_len: 3
          ref: sakila.inventory.inventory_id
         rows: 1
        Extra: Using where
*************************** 4. row ***************************
           id: 1
  select_type: SIMPLE
        table: customer
         type: eq_ref
possible_keys: PRIMARY,idx_fk_address_id
          key: PRIMARY
      key_len: 2
          ref: sakila.rental.customer_id
         rows: 1
        Extra: NULL
*************************** 5. row ***************************
           id: 1
  select_type: SIMPLE
        table: address
         type: eq_ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 2
          ref: sakila.customer.address_id
         rows: 1
        Extra: NULL

Looks a little cryptic though, doesn’t it? Other people thought so as well. Other MySQL tools were designed to help us get a better handle on what exactly the optimizer is planning to do.

Percona released pt-visual-explain to help us have a better representation:

JOIN
+- Bookmark lookup
|  +- Table
|  |  table          address
|  |  possible_keys  PRIMARY
|  +- Unique index lookup
|     key            address->PRIMARY
|     possible_keys  PRIMARY
|     key_len        2
|     ref            sakila.customer.address_id
|     rows           1
+- JOIN
   +- Bookmark lookup
   |  +- Table
   |  |  table          customer
   |  |  possible_keys  PRIMARY,idx_fk_address_id
   |  +- Unique index lookup
   |     key            customer->PRIMARY
   |     possible_keys  PRIMARY,idx_fk_address_id
   |     key_len        2
   |     ref            sakila.rental.customer_id
   |     rows           1
   +- JOIN
      +- Filter with WHERE
      |  +- Bookmark lookup
      |     +- Table
      |     |  table          rental
      |     |  possible_keys  idx_fk_inventory_id,idx_fk_customer_id
      |     +- Index lookup
      |        key            rental->idx_fk_inventory_id
      |        possible_keys  idx_fk_inventory_id,idx_fk_customer_id
      |        key_len        3
      |        ref            sakila.inventory.inventory_id
      |        rows           1
      +- JOIN
         +- Index lookup
         |  key            inventory->idx_fk_film_id
         |  possible_keys  PRIMARY,idx_fk_film_id
         |  key_len        2
         |  ref            sakila.film.film_id
         |  rows           1
         +- Table scan
            rows           1000
            +- Table
               table          film
               possible_keys  PRIMARY

The output is justified as such:

pt-visual-explain reverse-engineers MySQL’s EXPLAIN output into a query execution plan, which it then formats as a left-deep tree – the same way the plan is represented inside MySQL. It is possible to do this by hand, or to read EXPLAIN’s output directly, but it requires patience and expertise. Many people find a tree representation more understandable.

The folks that develop MySQL Workbench tried to give an actual visual explanation in their tool. It creates graphics of the predicted workflow, and changes the colors of different steps to highlight expensive parts of the query:

And finally, MySQL itself can output extended EXPLAIN information and always does so if you use the JSON output format (introduced in MySQL 5.6):

> EXPLAIN format=JSON SELECT CONCAT(customer.last_name, ', ', customer.first_name) AS customer,     address.phone, film.title     FROM rental INNER JOIN customer ON rental.customer_id = customer.customer_id     INNER JOIN address ON customer.address_id = address.address_id     INNER JOIN inventory ON rental.inventory_id = inventory.inventory_id     INNER JOIN film ON inventory.film_id = film.film_id     WHERE rental.return_date IS NULL     AND rental_date + INTERVAL film.rental_duration DAY < CURRENT_DATE()     LIMIT 5G
*************************** 1. row ***************************
EXPLAIN: {
  "query_block": {
    "select_id": 1,
    "nested_loop": [
      {
        "table": {
          "table_name": "film",
          "access_type": "ALL",
          "possible_keys": [
            "PRIMARY"
          ],
          "rows": 1000,
          "filtered": 100
        }
      },
      {
        "table": {
          "table_name": "inventory",
          "access_type": "ref",
          "possible_keys": [
            "PRIMARY",
            "idx_fk_film_id"
          ],
          "key": "idx_fk_film_id",
          "used_key_parts": [
            "film_id"
          ],
          "key_length": "2",
          "ref": [
            "sakila.film.film_id"
          ],
          "rows": 1,
          "filtered": 100,
          "using_index": true
        }
      },
      {
        "table": {
          "table_name": "rental",
          "access_type": "ref",
          "possible_keys": [
            "idx_fk_inventory_id",
            "idx_fk_customer_id"
          ],
          "key": "idx_fk_inventory_id",
          "used_key_parts": [
            "inventory_id"
          ],
          "key_length": "3",
          "ref": [
            "sakila.inventory.inventory_id"
          ],
          "rows": 1,
          "filtered": 100,
          "attached_condition": "(isnull(`sakila`.`rental`.`return_date`) and ((`sakila`.`rental`.`rental_date` + interval `film`.`rental_duration` day) < <cache>(curdate())))"
        }
      },
      {
        "table": {
          "table_name": "customer",
          "access_type": "eq_ref",
          "possible_keys": [
            "PRIMARY",
            "idx_fk_address_id"
          ],
          "key": "PRIMARY",
          "used_key_parts": [
            "customer_id"
          ],
          "key_length": "2",
          "ref": [
            "sakila.rental.customer_id"
          ],
          "rows": 1,
          "filtered": 100
        }
      },
      {
        "table": {
          "table_name": "address",
          "access_type": "eq_ref",
          "possible_keys": [
            "PRIMARY"
          ],
          "key": "PRIMARY",
          "used_key_parts": [
            "address_id"
          ],
          "key_length": "2",
          "ref": [
            "sakila.customer.address_id"
          ],
          "rows": 1,
          "filtered": 100
        }
      }
    ]
  }
}
1 row in set, 1 warning (0.00 sec)

Don’t worry if EXPLAIN looks a little daunting. EXPLAIN can be hard to explain. Just know that it tells you what it thinks is going to happen and in what order. You can familiarize yourself with it as you go along.

Now let’s say you’ve executed your query and want to find out what actually happened. Or maybe you have a server that is running a lot of queries and you want to visualize what is going on with this server. It’s time to examine the tools we use to analyze AFTER running queries.

Similar to EXPLAIN, MySQL has tools built into it to help you understand what happened after a query was run. Query profiling tells us what the query spent its time doing. You can get a profile directly from the MySQL console:

> set profiling=1;
Query OK, 0 rows affected, 1 warning (0.00 sec)
​
> SELECT CONCAT(customer.last_name, ', ', customer.first_name) AS customer,     address.phone, film.title     FROM rental INNER JOIN customer ON rental.customer_id = customer.customer_id     INNER JOIN address ON customer.address_id = address.address_id     INNER JOIN inventory ON rental.inventory_id = inventory.inventory_id     INNER JOIN film ON inventory.film_id = film.film_id     WHERE rental.return_date IS NULL     AND rental_date + INTERVAL film.rental_duration DAY < CURRENT_DATE()     LIMIT 5;
+----------------+--------------+------------------+
| customer       | phone        | title            |
+----------------+--------------+------------------+
| OLVERA, DWAYNE | 62127829280  | ACADEMY DINOSAUR |
| HUEY, BRANDON  | 99883471275  | ACE GOLDFINGER   |
| OWENS, CARMEN  | 272234298332 | AFFAIR PREJUDICE |
| HANNON, SETH   | 864392582257 | AFRICAN EGG      |
| COLE, TRACY    | 371490777743 | ALI FOREVER      |
+----------------+--------------+------------------+
5 rows in set (0.00 sec)
​
 > show profile;
+----------------------+----------+
| Status               | Duration |
+----------------------+----------+
| starting             | 0.000122 |
| checking permissions | 0.000006 |
| checking permissions | 0.000004 |
| checking permissions | 0.000003 |
| checking permissions | 0.000003 |
| checking permissions | 0.000005 |
| Opening tables       | 0.000026 |
| init                 | 0.000044 |
| System lock          | 0.000013 |
| optimizing           | 0.000020 |
| statistics           | 0.000058 |
| preparing            | 0.000024 |
| executing            | 0.000004 |
| Sending data         | 0.001262 |
| end                  | 0.000008 |
| query end            | 0.000006 |
| closing tables       | 0.000010 |
| freeing items        | 0.000021 |
| cleaning up          | 0.000014 |
+----------------------+----------+
19 rows in set, 1 warning (0.00 sec)

Or using performance_schema:

mysql> UPDATE performance_schema.threads SET INSTRUMENTED = 'NO'
       WHERE TYPE='FOREGROUND' AND PROCESSLIST_USER NOT LIKE 'test_user';
      
mysql> UPDATE performance_schema.setup_instruments SET ENABLED = 'YES', TIMED = 'YES'
       WHERE NAME LIKE '%statement/%';
​
mysql> UPDATE performance_schema.setup_instruments SET ENABLED = 'YES', TIMED = 'YES'
       WHERE NAME LIKE '%stage/%';      
​
mysql> UPDATE performance_schema.setup_consumers SET ENABLED = 'YES'
       WHERE NAME LIKE '%events_statements_%';
​
mysql> UPDATE performance_schema.setup_consumers SET ENABLED = 'YES'
       WHERE NAME LIKE '%events_stages_%';
      
> SELECT CONCAT(customer.last_name, ', ', customer.first_name) AS customer,     address.phone, film.title     FROM rental INNER JOIN customer ON rental.customer_id = customer.customer_id     INNER JOIN address ON customer.address_id = address.address_id     INNER JOIN inventory ON rental.inventory_id = inventory.inventory_id     INNER JOIN film ON inventory.film_id = film.film_id     WHERE rental.return_date IS NULL     AND rental_date + INTERVAL film.rental_duration DAY < CURRENT_DATE()     LIMIT 5;
+----------------+--------------+------------------+
| customer       | phone        | title            |
+----------------+--------------+------------------+
| OLVERA, DWAYNE | 62127829280  | ACADEMY DINOSAUR |
| HUEY, BRANDON  | 99883471275  | ACE GOLDFINGER   |
| OWENS, CARMEN  | 272234298332 | AFFAIR PREJUDICE |
| HANNON, SETH   | 864392582257 | AFRICAN EGG      |
| COLE, TRACY    | 371490777743 | ALI FOREVER      |
+----------------+--------------+------------------+
5 rows in set (0.00 sec)    
​
mysql> SELECT EVENT_ID, TRUNCATE(TIMER_WAIT/1000000000000,6) as Duration, SUBSTRING(SQL_TEXT,1,25) as sql_text
       FROM performance_schema.events_statements_history_long WHERE SQL_TEXT like '%rental%';
+----------+----------+--------------------------------------------------------+
| event_id | duration | sql_text                                               |
+----------+----------+--------------------------------------------------------+
|       31 | 0.028302 | SELECT CONCAT(customer.la                              |
+----------+----------+--------------------------------------------------------+
      
mysql> SELECT event_name AS Stage, TRUNCATE(TIMER_WAIT/1000000000000,6) AS Duration
       FROM performance_schema.events_stages_history_long WHERE NESTING_EVENT_ID=31;
+--------------------------------+----------+
| Stage                          | Duration |
+--------------------------------+----------+
| stage/sql/starting             | 0.000080 |
| stage/sql/checking permissions | 0.000005 |
| stage/sql/Opening tables       | 0.027759 |
| stage/sql/init                 | 0.000052 |
| stage/sql/System lock          | 0.000009 |
| stage/sql/optimizing           | 0.000006 |
| stage/sql/statistics           | 0.000082 |
| stage/sql/preparing            | 0.000008 |
| stage/sql/executing            | 0.000000 |
| stage/sql/Sending data         | 0.000017 |
| stage/sql/end                  | 0.000001 |
| stage/sql/query end            | 0.000004 |
| stage/sql/closing tables       | 0.000006 |
| stage/sql/freeing items        | 0.000272 |
| stage/sql/cleaning up          | 0.000001 |
+--------------------------------+----------+

This can be helpful if a query plan looks “good” but things are taking too long. You can find out if your query is spending time locked or compiling statistics, etc.

You can also find out “how much” of something was going on for a given query by looking at the handler statistics:

> FLUSH STATUS;
Query OK, 0 rows affected (0.00 sec)
​
> SELECT CONCAT(customer.last_name, ', ', customer.first_name) AS customer,     address.phone, film.title     FROM rental INNER JOIN customer ON rental.customer_id = customer.customer_id     INNER JOIN address ON customer.address_id = address.address_id     INNER JOIN inventory ON rental.inventory_id = inventory.inventory_id     INNER JOIN film ON inventory.film_id = film.film_id     WHERE rental.return_date IS NULL     AND rental_date + INTERVAL film.rental_duration DAY < CURRENT_DATE()     LIMIT 5;
+----------------+--------------+------------------+
| customer       | phone        | title            |
+----------------+--------------+------------------+
| OLVERA, DWAYNE | 62127829280  | ACADEMY DINOSAUR |
| HUEY, BRANDON  | 99883471275  | ACE GOLDFINGER   |
| OWENS, CARMEN  | 272234298332 | AFFAIR PREJUDICE |
| HANNON, SETH   | 864392582257 | AFRICAN EGG      |
| COLE, TRACY    | 371490777743 | ALI FOREVER      |
+----------------+--------------+------------------+
5 rows in set (0.00 sec)
​
> show status like 'Handler%';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Handler_commit             | 1     |
| Handler_delete             | 0     |
| Handler_discover           | 0     |
| Handler_external_lock      | 10    |
| Handler_mrr_init           | 0     |
| Handler_prepare            | 0     |
| Handler_read_first         | 1     |
| Handler_read_key           | 94    |
| Handler_read_last          | 0     |
| Handler_read_next          | 293   |
| Handler_read_prev          | 0     |
| Handler_read_rnd           | 0     |
| Handler_read_rnd_next      | 33    |
| Handler_rollback           | 0     |
| Handler_savepoint          | 0     |
| Handler_savepoint_rollback | 0     |
| Handler_update             | 0     |
| Handler_write              | 19    |
+----------------------------+-------+
18 rows in set (0.00 sec)

This allows us a glimpse of how many times MySQL had to do certain things while running a query. For instance “Handler_read_rnd_next” was used 33 times. We can look up what this means in the documents and gain insight into what is happening.

These tools allow us to have a better understanding of what happened when a query was executed. But again they only help us analyze a single query. If you really want to see a bigger picture of an overall server workload and what queries are doing in production, you need to bring out the big guns.

Percona toolkit offers pt-query-digest. This tool ingests a slow query log from the server and analyzes it to your specifications. Its output has some visualization (tabulation) that gives you a better idea of what a server is spending its time doing, and offers a break down of the individual queries and real-world examples.

A top-level overview:

# 8.1s user time, 60ms system time, 26.23M rss, 62.49M vsz
# Current date: Thu Dec 29 07:09:32 2011
# Hostname: somehost.net
# Files: slow-query.log.1
# Overall: 20.08k total, 167 unique, 16.04 QPS, 0.01x concurrency ________
# Time range: 2011-12-28 18:42:47 to 19:03:39
# Attribute          total     min     max     avg     95%  stddev  median
# ============     ======= ======= ======= ======= ======= ======= =======
# Exec time             8s     1us    44ms   403us   541us     2ms    98us
# Lock time          968ms       0    11ms    48us   119us   134us    36us
# Rows sent        105.76k       0    1000    5.39    9.83   32.69       0
# Rows examine     539.46k       0  15.65k   27.52   34.95  312.56       0
# Rows affecte       1.34k       0      65    0.07       0    1.35       0
# Rows read        105.76k       0    1000    5.39    9.83   32.69       0
# Bytes sent        46.63M      11 191.38k   2.38k   6.63k  11.24k  202.40
# Merge passes           0       0       0       0       0       0       0
# Tmp tables         1.37k       0      61    0.07       0    0.91       0
# Tmp disk tbl         490       0      10    0.02       0    0.20       0
# Tmp tbl size      72.52M       0 496.09k   3.70k       0  34.01k       0
# Query size         3.50M      13   2.00k  182.86  346.17  154.34   84.10
# InnoDB:
# IO r bytes        96.00k       0  32.00k   20.86       0  816.04       0
# IO r ops               6       0       2    0.00       0    0.05       0
# IO r wait           64ms       0    26ms    13us       0   530us       0
# pages distin      28.96k       0      48    6.29   38.53   10.74    1.96
# queue wait             0       0       0       0       0       0       0
# rec lock wai           0       0       0       0       0       0       0
# Boolean:
# Filesort       4% yes,  95% no
# Filesort on    0% yes,  99% no
# Full scan      4% yes,  95% no
# QC Hit         0% yes,  99% no
# Tmp table      4% yes,  95% no
# Tmp table on   2% yes,  97% no

An individual query overview:

# Query 1: 0.26 QPS, 0.00x concurrency, ID 0x92F3B1B361FB0E5B at byte 14081299
# This item is included in the report because it matches --limit.
# Scores: Apdex = 1.00 [1.0], V/M = 0.00
# Query_time sparkline: |   _^   |
# Time range: 2011-12-28 18:42:47 to 19:03:10
# Attribute    pct   total     min     max     avg     95%  stddev  median
# ============ === ======= ======= ======= ======= ======= ======= =======
# Count          1     312
# Exec time     50      4s     5ms    25ms    13ms    20ms     4ms    12ms
# Lock time      3    32ms    43us   163us   103us   131us    19us    98us
# Rows sent     59  62.41k     203     231  204.82  202.40    3.99  202.40
# Rows examine  13  73.63k     238     296  241.67  246.02   10.15  234.30
# Rows affecte   0       0       0       0       0       0       0       0
# Rows read     59  62.41k     203     231  204.82  202.40    3.99  202.40
# Bytes sent    53  24.85M  46.52k  84.36k  81.56k  83.83k   7.31k  79.83k
# Merge passes   0       0       0       0       0       0       0       0
# Tmp tables     0       0       0       0       0       0       0       0
# Tmp disk tbl   0       0       0       0       0       0       0       0
# Tmp tbl size   0       0       0       0       0       0       0       0
# Query size     0  21.63k      71      71      71      71       0      71
# InnoDB:
# IO r bytes     0       0       0       0       0       0       0       0
# IO r ops       0       0       0       0       0       0       0       0
# IO r wait      0       0       0       0       0       0       0       0
# pages distin  40  11.77k      34      44   38.62   38.53    1.87   38.53
# queue wait     0       0       0       0       0       0       0       0
# rec lock wai   0       0       0       0       0       0       0       0
# Boolean:
# Full scan    100% yes,   0% no
# String:
# Databases    wp_blog_one (264/84%), wp_blog_tw… (36/11%)... 1 more
# Hosts
# InnoDB trxID 86B40B (1/0%), 86B430 (1/0%), 86B44A (1/0%)... 309 more
# Last errno   0
# Users        wp_blog_one (264/84%), wp_blog_two (36/11%)... 1 more
# Query_time distribution
#   1us
#  10us
# 100us
#   1ms  #################
#  10ms  ################################################################
# 100ms
#    1s
#  10s+
# Tables
#    SHOW TABLE STATUS FROM `wp_blog_one ` LIKE 'wp_options'G
#    SHOW CREATE TABLE `wp_blog_one `.`wp_options`G
# EXPLAIN /*!50100 PARTITIONS*/
SELECT option_name, option_value FROM wp_options WHERE autoload = 'yes'G

Use it if you have a representative example of a server’s workload and you’re trying to understand what queries are the most poorly performing or executed most often. You can look for outliers that cause problems on occasion and more.

Finally, in the modern world, we want all this data aggregated together, visualized and easily accessible. Everything from explains to statistics to profiles to digests, and we want it all compiled in a nice neat package. Enter Percona Monitoring and Management (PMM) Query Analytics. (Screenshots are from PMM v1.7, other versions may look different.)

After setup and configuration, this tool offers us a comprehensive visual representation of the things we’ve discussed and much more.

PMM QAN is able to offer us a big picture look at the queries a server is executing, when they’re being run, what is taking up a lot of time, and what the variance is for a user defined time frame. It does this all at a glance by offering sparkline graphs (timelines) and variance represented graphically:

     

Remember when I spoke about Handlers and Profiling? PMM also offers us an aggregated picture of similar information server wide with human-readable terminology:

By selecting a single query, you can “drill down” and get lots of details about that specific query being run on your server:

Along with immediate access to Schema infomation and explain plans:


You can see PMM QAN in action (along with the rest of PMM’s features) at the demo site:

https://pmmdemo.percona.com/

As you can see there are many ways we can use MySQL tools to help us visualize what MySQL is doing with a query. Knowing what tools are available and what they can show you about your query can be helpful. Some of these are very quick and easy to use, such as the built-in MySQL utility statements. Others like pt-toolkit or Workbench require installed software, and pt-query-digest usually needs a representative query log. PMM requires installation and configuration, but it provides the most detail and visualization.

MySQL tools we discussed:

RDS Aurora MySQL Cost

$
0
0

big bag of money getting carriedI promised to do a pricing post on the Amazon RDS Aurora MySQL pricing, so here we go.  All pricing is noted in USD (we’ll explain why)

We compared pricing of equivalent EC2+EBS server instances, and verified our calculation model with Amazon’s own calculator and examples.  We use the pricing for Australia (Sydney data centre). Following are the relevant Amazon pricing pages from which we took the pricing numbers, formulae, and calculation examples:

Base Pricing Details

Specs         EC2     RDS Aurora MySQL  
instance type vCPU ECU GB RAM   Storage Linux/hr   instance type Price/hr
r4.large 2 7 15.25 EBS Only $0.160 db.r4.large $0.350
r4.xlarge 4 13.5 30.5 EBS Only $0.319 db.r4.xlarge $0.700
r4.2xlarge 8 27 61 EBS Only $0.638 db.r4.2xlarge $1.400
r4.4xlarge 16 53 122 EBS Only $1.277 db.r4.4xlarge $2.800
r4.8xlarge 32 99 244 EBS Only $2.554 db.r4.8xlarge $5.600
r4.16xlarge 64 195 488 EBS Only $5.107 db.r4.16xlarge $11.200

That’s not all we need, because both EBS and Aurora have some additional costs we need to factor in.

EBS pricing components (EBS Provisioned IOPS SSD (io1) volume)

“Volume storage for EBS Provisioned IOPS SSD (io1) volumes is charged by the amount you provision in GB per month until you release the storage. With Provisioned IOPS SSD (io1) volumes, you are also charged by the amount you provision in IOPS (input/output operations per second) per month. Provisioned storage and provisioned IOPS for io1 volumes will be billed in per-second increments, with a 60 second minimum.”

  • Storage Rate $0.138 /GB/month of provisioned storage
    “For example, let’s say that you provision a 2000 GB volume for 12 hours (43,200 seconds) in a 30 day month. In a region that charges $0.125 per GB-month, you would be charged $4.167 for the volume ($0.125 per GB-month * 2000 GB * 43,200 seconds / (86,400 seconds/day * 30 day-month)).”
  • I/O Rate $0.072 /provisioned IOPS-month
    “Additionally, you provision 1000 IOPS for your volume. In a region that charges $0.065 per provisioned IOPS-month, you would be charged $1.083 for the IOPS that you provisioned ($0.065 per provisioned IOPS-month * 1000 IOPS provisioned * 43,200 seconds /(86,400 seconds /day * 30 day-month)).”

Other Aurora pricing components

  • Storage Rate $0.110 /GB/month
    (No price calculation examples given for Aurora storage and I/O)
  • I/O Rate $0.220 /1 million requests
    (Presuming IOPS equivalence / Aurora ratio noted from arch talk)

So this provides us with a common base, instance types that are equivalent between Aurora and EC2.  All other Aurora instances types are different, so it’s not possible to do a direct comparison in those cases.  Presumably we can make the assumption that the pricing ratio will similar for equivalent specs.

On Demand vs Reserved Instances

We realise we’re calculating on the basis of On Demand pricing.  But we’re comparing pricing within AWS space, so presumably the savings for Reserved Instances are in a similar ballpark.

Other factors

  • We have 720 hours in a 30 day month, which is 2592000 seconds.
  • 70% read/write ratio – 70% reads (used to calculate the effective Aurora IOPS)
  • 10% read cache miss -10% cache miss rate on reads
  • Aurora I/O ratio: 3 (Aurora requiring 2 IOPS for a commit vs 6 in MySQL – even though this is a pile of extreme hogwash in terms of that pessimistic MySQL baseline)

We also spotted this note regarding cross-AZ Aurora traffic:

“Amazon RDS DB Instances inside VPC: For data transferred between an Amazon EC2 instance and Amazon RDS DB Instance in different Availability Zones of the same Region, Amazon EC2 Regional Data Transfer charges apply on both sides of transfer.”

So this would apply to application DB queries issued across an AZ boundary, which would commonly happen during failover scenarios.  In fact, we know that this happens during regular operations with some EC2 setups, because the loadbalancing already goes cross-AZ.  So that costs extra also.  Now you know!  (note: we did not factor this in to our calculations.)

Calculation Divergence

Our model comes up with identical outcomes for the examples Amazon provided, however it comes up 10-15% lower than Amazon’s calculator for specific Aurora configurations.  We presume that the difference may lie in the calculated Aurora I/O rate, as that’s the only real “unknown” in the model.  Amazon’s calculator does not show what formulae it uses for the sub-components, nor sub-totals, and we didn’t bother to tweak until we got at the same result.

It’s curious though, as the the architecture talk makes specific claims about Aurora’s I/O efficiency (which presume optimal Aurora situation and a dismal MySQL reference setup, something which I already raised in our initial Aurora post).  So apparently the Amazon calculator assumes worse I/O performance than the technical architecture talk!

Anyhow, let’s just say our costing is conservative, as the actual cost is higher on the Aurora end.

Scenarios

Here we compare with say a MySQL/MariaDB Galera setup across 3 AZs running on EC2+EBS.  While this should be similar in overall availability and read-capacity, note that

  1. you can write to all nodes in a Galera cluster, whereas Aurora currently has a single writer/master;
  2. Galera doesn’t require failover changes as all its nodes are technically writers anyhow, whereas Aurora failover causes a cluster outage of at least 30 seconds.
Servers R/Zones Instance GB DB I/O rate     EC2 EBS     Aurora      
          Read IOPS   Instances Storage I/O EC2 Total   Instances Storage I/O Aurora Total
3 3 r4.xlarge 250 2,000 740 $689 $104 $160 $952   $1,512 $83 $141 $1,735
6 3 r4.xlarge 250 2,000 740 $1,378 $207 $320 $1,905   $3,024 $83 $141 $3,247
     

When using the Amazon calculator, Aurora comes out at about double the EC2.  But don’t take our word for it, do try this for yourself.

Currency Consequences

While pricing figures are distinct per country that Amazon operates in, the charges are always in USD.  So this means that the indicated pricing is, in the end, in USD, and thus subject to currency fluctuations (if your default currency is not USD).  What does this mean?

USD AUD rate chart 2008-2018
USD-AUD rate chart 2008-2018, from xe.com

So USD 1,000 can cost as little as AUD 906 or as much as AUD 1,653, at different times over the last 10 years.  That’s quite a range!

Conclusion

As shown above, our calculation with Aurora MySQL shows it costing about twice as much.  This is based on a reference MySQL/MariaDB+Galera with roughly the same scaling and resilience profile (e.g. the ability to survive DC outages).  In functional terms, particularly with Aurora’s 30+second outage profile during failover, Galera comes out on top at half the cost.

So when is Aurora cheaper, as claimed by Amazon?

Amazon makes claims in the realm of “1/10th the cost”. Well, that may well be the case when comparing with the TCO of Oracle or MS SQL Server, and it’s fairly typical when comparing a proprietary system with an Open Source based one (mind again that Aurora is not actually Open Source as Amazon does not make their source code available, but it’s based on MySQL).

The only other way we see is to seriously compromise on the availability (resilience).  In our second sample calculation, we use 2 instances per AZ.  This is not primarily for performance, but so that application servers in an AZ don’t have to do cross-DC queries when one instance fails.  In the case of Aurora, spinning up a new instance on the same dataset requires 15 minutes.  So, do you want to take that hit?  If so, you can save money there.  If not, it’s still costly.

But hang on, if you’re willing to make the compromise on availability, you could reduce the Galera setup also, to only one instance per AZ.  Yep!

So, no matter how you tweak it, Aurora is about twice the cost, with (in our opinion) a less interesting failover profile.

The Price of RDS Convenience

What you get with RDS/Aurora is the promise of convenience, and that’s what you pay for.  But, mind that our comparison worked all within AWS space anyway, the EC2 instances we used for MySQL/MariaDB+Galera already use the same basic infrastructure, dashboard and management API as well.  So you pay double just to go to RDS/Aurora, relative to building on EC2.

To us, that cost seems high.  If you spend some, or even all that money on engineering that convenience around your particular setup, and even outsource that task and its maintenance, you get a nicer setup at the same or a lower cost.  And last but not least, that cost will be more predictable – most likely the extra work will be charged in your own currency, too.

Cost Predictability and Budget

You can do a reasonable ball-park calculation of AWS EC2 instances that are always active, but EBS already has some I/O charges which make the actual cost rather more variable, and Aurora adds a few more variables on top of that.  I’m still amazed that companies go for this, even though they traditionally prefer a known fixed cost (even if higher) over a variable cost.  Choosing the variable cost breaks with some fundamental business rules, for the sake of some convenience.

The advantage of known fixed costs is that you can budget properly, as well as project future costs based on growth and other business factors.  Purposefully ditching that realm, while exposing yourself to currency fluctuations at the same time, seems most curious.  How do companies work this into their budgets?  Because others do so?  Well, following the neighbours is not always a good idea.  In this case, it might be costly as well as financially risky.

Failover for MySQL Replication (and others) - Should it be Automated?

$
0
0

Automatic failover for MySQL Replication has been subject to debate for many years.

Is it a good thing or a bad thing?

For those with long memory in the MySQL world, they might remember the GitHub outage in 2012 which was mainly caused by software taking the wrong decisions.

GitHub had then just migrated to a combo of MySQL Replication, Corosync, Pacemaker and Percona Replication Manager. PRM decided to do a failover after failing health checks on the master, which was overloaded during a schema migration. A new master was selected, but it performed poorly because of cold caches. The high query load from the busy site caused PRM heartbeats to fail again on the cold master, and PRM then triggered another failover to the original master. And the problems just continued, as summarized below.

Fast forward a couple of years and GitHub is back with a pretty sophisticated framework for managing MySQL Replication and automated failover! As Shlomi Noach puts it:

“To that effect, we employ automated master failovers. The time it would take a human to wake up & fix a failed master is beyond our expectancy of availability, and operating such a failover is sometimes non-trivial. We expect master failures to be automatically detected and recovered within 30 seconds or less, and we expect failover to result in minimal loss of available hosts.”

Most companies are not GitHub, but one could argue that no company likes outages. Outages are disruptive to any business, and they also cost money. My guess is that most companies out there probably wished they had some sort of automated failover, and the reasons not to implement it are probably the complexity of the existing solutions, lack of competence in implementing such solutions, or lack of trust in software to take such an important decision.

There are a number of automated failover solutions out there, including (and not limited to) MHA, MMM, MRM, mysqlfailover, Orchestrator and ClusterControl. Some of them have been on the market for a number of years, others are more recent. That is a good sign, multiple solutions mean that the market is there and people are trying to address the problem.

When we designed automatic failover within ClusterControl, we used a few guiding principles:

  • Make sure the master is really dead before you failover

    In case of a network partition, where the failover software loses contact with the master, it will stop seeing it. But the master might be working well and can be seen by the rest of the replication topology.

    ClusterControl gathers information from all the database nodes as well as any database proxies/load balancers used, and then builds a representation of the topology. It will not attempt a failover if the slaves can see the master, nor if ClusterControl is not 100% sure about the state of the master.

    ClusterControl also makes it easy to visualize the topology of the setup, as well as the status of the different nodes (this is ClusterControl’s understanding of the state of the system, based on the information it gathers).

  • Failover only once

    Much has been written about flapping. It can get very messy if the availability tool decides to do multiple failovers. That’s a dangerous situation. Each master elected, however brief the period it held the master role, might have their own sets of changes that were never replicated to any server. So you may end up with inconsistency across all the elected masters.

  • Do not failover to an inconsistent slave

    When selecting a slave to promote as master, we ensure the slave does not have inconsistencies, e.g. errant transactions, as this may very well break replication.

  • Only write to the master

    Replication goes from the master to the slave(s). Writing directly to a slave would create a diverging dataset, and that can be a potential source of problem. We set the slaves to read_only, and super_read_only in more recent versions of MySQL or MariaDB. We also advise the use of a load balancer, e.g., ProxySQL or MaxScale, to shield the application layer from the underlying database topology and any changes to it. The load balancer also enforces writes on the current master.

  • Do not automatically recover the failed master

    If the master has failed and a new master has been elected, ClusterControl will not try to recover the failed master. Why? That server might have data that has not yet been replicated, and the administrator would need to do some investigation into the failure. Ok, you can still configure ClusterControl to wipe out the data on the failed master and have it join as a slave to the new master - if you are ok with losing some data. But by default, ClusterControl will let the failed master be, until someone looks at it and decides to re-introduce it into the topology.

So, should you automate failover? It depends on how you have configured replication. Circular replication setups with multiple write-able masters or complex topologies are probably not good candidates for auto failover. We would stick to the above principles when designing a replication solution.

On PostgreSQL

When it comes to PostgreSQL streaming replication, ClusterControl uses similar principles to automate failover. For PostgreSQL, ClusterControl supports both asynchronous and synchronous replication models between the master and the slaves. In both cases and in the event of failure, the slave with the most up-to-date data is elected as the new master. Failed masters are not automatically recovered/fixed to rejoin the replication setup.

There are a few protective measures taken to make sure the failed master is down and stays down, e.g. it is removed from the load balancing set in the proxy and it is killed if e.g. the user would restart it manually. It is a bit more challenging there to detect network splits between ClusterControl and the master, since the slaves do not provide any information about the status of the master they are replicating from. So a proxy in front of the database setup is important as it can provide another path to the master.

On MongoDB

MongoDB replication within a replicaset via the oplog is very similar to binlog replication, so how come MongoDB automatically recovers a failed master? The problem is still there, and MongoDB addresses that by rolling back any changes that were not replicated to the slaves at the time of failure. That data is removed and placed in a ‘rollback’ folder, so it is up to the administrator to restore it.

To find out more, check out ClusterControl; and feel free to comment or ask questions below.

This Week in Data with Colin Charles 30: Schedule for Percona Live, and Tracking Those Missing Features

$
0
0
Colin Charles

Colin CharlesJoin Percona Chief Evangelist Colin Charles as he covers happenings, gives pointers and provides musings on the open source database community.

Have you registered for Percona Live already? The tutorial grid, the schedules for day 1 and day 2 are pretty amazing, and there is even an extra track being added, for a total of 10 concurrent/parallel tracks during day 1 & day 2. If you submitted a talk and it didn’t get accepted (competition was high), you should have received a discount code to register for the event.

I plan to write more dedicated blog posts around M|18 and the MariaDB Developer’s Unconference. Hang on till next week? I gave my presentation, targeted at developers, titled MySQL features missing in MariaDB Server. It was a room of maybe 40-45 people, and had some debate, but not much more; there were some other excellent presentations as well.

Next week, Percona will be at SCALE16x. We are sponsors, so there will also be a booth (where you can get some interesting schwag), and don’t forget that both Peter Zaitsev and I have a talk (one on Friday, the other on Saturday). Looking forward to seeing you all there.

Releases

Link List

Upcoming appearances

  • SCALE16x – Pasadena, California, USA – March 8-11 2018
  • FOSSASIA 2018 – Singapore – March 22-25 2018

Feedback

I look forward to feedback/tips via e-mail at colin.charles@percona.com or on Twitter @bytebot.

 

Percona XtraDB Cluster 5.7.21-29.26 Is Now Available

$
0
0
Percona XtraDB Cluster 5.7

Percona XtraDB Cluster 5.6Percona announces the release of Percona XtraDB Cluster 5.7.21-29.26 (PXC) on March 2, 2018. Binaries are available from the downloads section or our software repositories.

Percona XtraDB Cluster 5.7.21-29.26 is now the current release, based on the following:

Starting from now, Percona XtraDB Cluster issue tracking system is moved from launchpad to JIRA. All Percona software is open-source and free.

Fixed Bugs

  • PXC-2039: Node consistency was compromised for INSERT INTO ... ON DUPLICATE KEY UPDATE workload because the regression introduced in Percona XtraDB Cluster 5.7.17-29.20made it possible to abort local transactions without further re-evaluation in case of a lock conflict.
  • PXC-2054 Redo optimized DDL operations (like sorted index build) were not blocked in case of a running backup process, leading to SST failure. To fix this, --lock-ddl option blocks now all DDL during the xtrabackup backup stage.
  • General code improvement was made in the GTID event handling, when events are captured as a part of the slave replication and appended to the Galera replicated write-set. This fixed PXC-2041 (starting async slave on a single node Percona XtraDB Cluster led to a crash) and PXC-2058 (binlog-based master-slave replication broke the cluster) caused by the incorrect handling in the GTID append logic.
  • An issue caused by non-coincidence between the order of recovered transaction and the global seqno assigned to the transaction was fixed ensuring that the updated recovery wsrep coordinates are persisted.
  • PXC-904: Replication filters were not working with account management statements like CREATE USER in case of Galera replication; as a result, such commands were blocked by the replication filters on async slave nodes but not on Galera ones.
  • PXC-2043: SST script was trying to use pv (the pipe viewer) for progress and rlimit options even on nodes with no pv installed, resulting in SST fail instead of just ignoring these options for inappropriate nodes.
  • PXC-911: When node’s own IP address was defined in the wsrep_cluster_address variable, the node was receiving “no messages seen in” warnings from its own IP address in the info log.

This release also contains fixes for the following CVE issues: CVE-2018-2565, CVE-2018-2573, CVE-2018-2576, CVE-2018-2583, CVE-2018-2586, CVE-2018-2590, CVE-2018-2612, CVE-2018-2600, CVE-2018-2622, CVE-2018-2640, CVE-2018-2645, CVE-2018-2646, CVE-2018-2647, CVE-2018-2665, CVE-2018-2667, CVE-2018-2668, CVE-2018-2696, CVE-2018-2703, CVE-2017-3737.

Help us improve our software quality by reporting any bugs you encounter using our bug tracking system. As always, thanks for your continued support of Percona!

Viewing all 18816 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>