Materialized view in mysql - mysql

How to create a materialized view in mysql ?
I am not able to create a materialized view as we do in MS SQL Server.
Could anyone let me know the ways to create it in mysql.

Here's what I've had success with so far:
Using triggers - you can set triggers on the source tables on which you build the view. This minimizes the resource usage as the refresh is only done when needed. Also, data in the materialized view is realtime-ish
Using cron jobs with stored procedures or SQL scripts - refresh is done on a regular basis. You have more control as to when resources are used. Obviously you data is only as fresh as the refresh-rate allows.
Using MySQL scheduled events - similar to 2, but runs inside the database
Flexviews - using FlexDC mentioned by Justin. The closest thing to real materialized views
I've been collecting and analyzing these methods, their pros and cons in my article Creating MySQL materialized views
looking forwards for feedback or proposals for other methods for creating materialized views in MySQL

You can create a non-updateable dynamic view - and if you've got (indexed) timestamps in the underlying table(s) you can add in a snapshot, something like:
CREATE VIEW almost_materialzd
AS
SELECT snp.*
FROM snapshot snp
WHERE s.id NOT IN (SELECT id
FROM source_data sd
INNER JOIN ref_data rd
ON rd.value='snapshot of source_data'
AND sd.update_timestamp>rd.timetamp)
UNION
SELECT *
FROM source_data sd2
INNER JOIN ref_data rd2
ON rd2.value='snapshot of source_data'
AND sd2.update_timestamp>rd2.timetamp);
But a better solution is to add a trigger (or triggers) to the the underlying table(s) to re-populate the relevant rows in a table representing the materialized view when the underlying tables are changed.

www.LeapDB.com provides MySQL materialized views. straight forward with the proper syntax. It's an add on to MySQL.

Related

Getting SHOW CREATE TABLE from a view, as if it were a table

I have access to a remote database, and I would like to dump the schema and data of several views onto my local machine and load this into my local database as tables in a quick and easy way.
I lack the user privileges to run CREATE TABLE AS (SELECT * FROM target_view), otherwise this would be trivial to solve. In other words, I want to retrieve and recreate the "composite" schema of target_view as if it were a table.
I do not want the output of SHOW CREATE VIEW, as this only shows a complex SELECT statement with joins to various tables on remote I have limited ability to access. And a problem I'm seeing in MySQL 8.x is when I run SHOW CREATE TABLE on the view, this command simply acts as an alias of SHOW CREATE VIEW (which is reasonable).
Frustratingly, I can run DESCRIBE and see the schema of these views as they were tables. I really just need to convert this information into a CREATE TABLE statement without actually being able to run CREATE TABLE.
In case it weren't obvious, the key is to avoid manual reconstruction of these views' tabular schemas (as they may change in the future). I also want to avoid the solution of reverse engineering a generic table construction of 20-30 generic VARCHAR or TEXT columns from a CSV dump.
I don't know of any way to display the metadata of a result set in CREATE TABLE syntax.
What I would do given your circumstance is first create on your local MySQL instance the base table and the view, then you can use the CREATE TABLE AS SELECT ... syntax to produce a concrete table to match the metadata of the view result set.

CREATE OR REPLACE VIEW Vs Checking view existing or not?

I am using Maria DB 5.5 version and it does not allow clause ‘CREATE VIEW IF NOT EXISTS’ while view creation. As requirement, I need to check whether view existing or not while creation.
Here I have 2 approach for this problem …
Do SQL using INFORMATION_SCHEMA.TABLES and create the view only if view is not present
Use ‘CREATE OR REPLACE VIEW’ so that no error/warning should throw if view is already present if view might have to handle more than 50k records.
Out of these 2 options, which options is better & recommended approach?
If you must know whether the view existed before your operation, using the information schema is helpful.
Otherwise, CREATE OR REPLACE is much simpler. Your view definition can stand alone as a DDL statement.
The first option requires the server to process several queries, so it will take slightly longer than the second option. But view creation (in MySQL and MariaDB) is very fast: no actual data is retrieved until you use the view in a query.
So the VIEW contains an ever-growing UNION across many databases. So, the only way the VIEW would not exist is when two new users are updating the view 'simultaneously'.
Suggested workaround:
SELECT GET_LOCK('update_view');
DROP VIEW ...;
CREATE VIEW ...;
SELECT RELEASE_LOCK('update_view');
This avoids the need for OR REPLACE (etc), except for the very first time -- when the DROP VIEW will complain that the VIEW does not exist. That can be solved by creating a dummy VIEW when the machine is first configured.
(Study the parameters on GET_LOCK.)

MySQL views performance with select * from tablename definition

I have created views with following generic definition on all of my tables required for reporting
select * from tablename
Ideally views with this definition should use merge algorithm.
Can someone please tell me if the performance of these views with the above definition will be comparable to the physical tables?
Check out this link.
By above report, derived table shows poor performance than table, while simple view works good. But if you run a query with ORDER or WHERE on view, it will be slower than naive table. (see comments on the link )
And use EXPLAIN to checkout your queries between view and table.

What is the best way to filter a multi-tenant MySQL database?

In MySQL I have a single database with one schema. In Microsoft Sql Server it is recommended to use a "Tenant View Filter" so in Microsoft Sql Server this gives me exactly what I need.
CREATE VIEW TenantEmployees AS
SELECT * FROM Employees WHERE TenantID = SUSER_SID()
What is the best way to accomplish the same in MySQL? An equivalent to the "Tenant View Filter" will work if it is performs well.
Thanks!!
The query you suggest (that I could find in MSDN) has text afterwards that explains exactly what are its assumptions. In particular, it mentions that it assumes that the "owner" of a row in the Employees table is specified in the TenantID field that is populated according to the SID of the user(s) you are partitioning for.
What that means is that you can replicate the same idea whatever way you decide to implement your data as long as you have clearly defined partitions of the data and know exactly how to associate it with the table you are creating a view for.
In particular, if you configure your system so that each partition accesses the DB with its own credentials, you could use the CURRENT_USER or USER constructs of MySQL as the IDs defining your partitions and the query to create the view would be basically the same as the one suggested in MSDN replacing SUSER_ID with CURRENT_USER.
But if you use the same user to access from all the partitions, then the suggested method is irrelevant on either database server.
Since you need to use your tenantId value to perform filtering, a table valued user defined function would be ideal, as a view normally does not accept parameters. Unfortunately, unlike many other database products MySQL doesn't support table-valued functions. However, there are MySQL hacks that claim to emulate parametrized views. These could be useful for you.
It's a little tricky in MySQL, but it can be done:
CREATE OR REPLACE VIEW {viewName}
AS
SELECT {fieldListWithoutTenantID}
FROM {tableName}
WHERE (id_tenant = SUBSTRING_INDEX(USER( ),'#',1))
I wrote up a full blog post on how I converted a single-tenant MySQL application to multi-tenant in one weekend with minimal changes. https://opensource.io/it/mysql-multi-tenant/

Using a table in another database

I've been asked to build a module for a web application, which will also be used as a stand alone website. Since this is the case, I wanted to use a separate database, and wondered if there was a way of having a table in one database, be a "pointer" in another database.
For example, I have databases db1 and db2
db1 has table users, so I want to have db2.users point to db1.users.
I know I could setup triggers and what not to sync two seperate tables but this sounds cooler :)
EDIT
So in my code I'm using sql such as
select * from users
Now, at the database level, I want "users" to actually be db1.users. Then, if I want to, I can remove the alias/pointer and "select * from users" will point to the users table in the current database. I guess what I'm looking for is a "global alias" type of thing.
Just use it directly from another database?
SELECT ... FROM `db1`.`users` LEFT JOIN `db2`.`something`
The federated storage engine offers something similar to the feature you asked for.
And if your databases are on the same database server, the federated storage enging sounds a bit like an overkill to me. You may want to create a view instead.
Both methods won't be useful if db1 is not available. As Emmerman already points out, you need to store the data in db2 if you want to prepare for the case of db1 being unavailable.