organizing multi-tenant db/MySQL [SaaS] - mysql

Good example will be shopify. Where you have N number of users (in this case each user assume site). And each user will have it's own records in DB. But db schema will be the same (same tables for each user, products, customers, orders etc.).
So question is what will be the best way to organize this kind of solution?
Store everything in one DB but in a different tables, or run separate DB for each user (but then will be question with maintaining, scalability and automatization)
possible solution:
We can use one DB with common tables like products, customers, orders etc. And we will have table users where we store records about each site.
In tables products, customers we will group all records by user_id.
This is one of possible solutions. But if we will have 1000 users (sites), each will have ~2k products, and ~100k customers, we can end up with tables which has millions of records, so questions will be:
how it will perform compare to each user (site) would have it's own DB?
how reliable this approach? bigger data, harder maintain, backup/restore
safety, if something wrong with one source thousands will be affected
Any links etc. will be much appreciated, thanks!

Create a mysql user for each tenant
Add a tenant_id column to each table
Add a view for each table that filters based on tenant_id = mysql_user
Use a trigger to automatically populate the tenant_id column on INSERT
Restrict the tenant mysql users to only access the views, not the raw tables
I wrote up a blog post on how I was able to convert a large single-tenant mysql application to a multi-tenant application in a weekend using this technique.
https://opensource.io/it/mysql-multi-tenant/

I recommend reviewing databases by well-supported open source solutions. With this in mind, here's a pretty simple schema I found real quick that'd explain a good working solution for this with scale-ability in mind.
http://www.zentut.com/sql-tutorial/sql-sample-database/

I have this file Generate_multiTanentMysql.php i do all steps with PHP script
https://github.com/ziedtuihri/SaaS_Application
Solution Design Pattern :
Creating a database user for each tenant
Renaming every table to a different and unique name (e.g. using a prefix ‘someprefix_’)
Adding a text column called ‘id_tenant’ to every table to store the name of the tenant the row belongs to
Creating a trigger for each table to automatically store the current database username to the id_tenant column before inserting a new row
Creating a view for each table with the original table name with all the columns except id_tenant. The view will only return rows where (id_tenant = current_database_username)
Only grant permission to the views (not tables) to each tenant’s database user Then, the only part of the application that needs to change is the database connection logic. When someone connects to the SaaS, the application would need to:
Connect to the database as that tenant-specific username

Related

SQL Database architecture with multiple end Users

I am making a web application where users get and manage data from multiple tables as well as create other users to access said data. currently I have it set up for one group of users.
My question is would it be better to have multiple databases in which each database has its own user which is stored in a master table("I don't like the sound of this one") or have a column in each table defining the user group that has access to it? Are either of these a good idea or is something else more appropriate?
You should have a column in each table. In my opinion, its the correct thing to do, and also you have only one database to do mantainance.
Just imagine the time it would take to add a column to a table in the future, and you should do it in multiple databases.

Need help in designing a database schema for a SaaS application

I am a developer and have never worked on DB before (designing a DB). I am designing a database for an employee management system which is a Node.js + Express application using MySQL as its DB.
I already have the required tables, columns sorted out but there are still few unknowns I am dealing with. This is my plan so far and I need your input on it.
The end users using this application will be small - mid size companies. The companies won't be sharing the tables in the database. So if there is a table named EmployeeCases I plan to create a new EmployeeCases table for each existing company or a new one who signs up for this application. I am planning to name the table as EmployeeCases_989809890 , where "989809890" will be the company id (or customer id). So if we have 3-4 companies who signed up for us, then all the tables (at least the ones which a company uses) will be recreated and named as TableName_CompanyId. My questions, is this a good way to go? Is there a better way?
All the employee's data is held by the Employee table, including their login and password. Now each Employee table in DB will be named as Employee_CompanyId (as per my plan above). My question is, when an employee logs in, how will I know which Employee table to query to? Or should I remove the login from the Employee table and create a universal Users table where all the employees will be stored? The Users table will also have the CompanyId as one of its column and I will read the CompanyId from there which will be used to query other tables.
Any reference, website or blogs on this type of design will be appreciated.
Thanks.
I don't recommend this approach, I think you should either:
A) Put all the information in the same tables and have a companyId column to sort them out
OR
B) Have separate databases for each company and use the appropriate database using the code.
The thing is, with your approach, you'll have a hard time maintaining your application if you have multiple copies of the same table with different names. If you decide to add a column to one of the tables, for instance, you will have to write as many SQL scripts as you have table instances. You'll also have a bad time with all of your unique identifiers.
Here are some advantages/disadvantages of each design:
A) Put all the information in the same tables and have a compagnyId column to sort them out
Advantages:
Simplest
Allow usage of foreign key / constraints
Great for cross / client data extraction
Disadvantages:
Not portable (a client can't just leave with his/her data)
Can be perceived as less secure (I guess you can make the case both ways)
More likely to have huge tables
Does not scale very well
B) Have separate databases for each company and use the appropriate database using the code.
Advantages:
Portable
Can be perceived as more secure
Disadvantages:
Needs more discipline to keep track of all the databases
Needs a good segregation of what's part of your HUB (Your application that tracks which client access which database) and that's part of your client's database.
You need a login page by company (or have your clients specify the company in a field)
An example of an application that uses this "two-step login" is Slack, when you sign-in you first enter your team domain THEN your user credentials.
I think Google Apps for Work as the same approach. Also, I think most CRM I worked with has a separate database for their clients.
Lastly, I'd like to direct you to this other question on stackoverflow that links to an interesting example.
You shouldn't split your tables just because companies won't share their information. Instead, you should have a companyId column in each table and access to the relevant data for each query. This should be implemented in your backend

how can create message system for a lot of users without much proccess of time in mysql?

I want design a inside system message for about 10000 user!
Steps seem easy:
1- create a DB table. for example: Message
2- create an user table. for example : user
3- the search Message DB and return all messages to user.
but you know for all 10000 user is too much time with one table to access messages.
My plan is create a independent table for each user for keep his messages. (not one table for all users)
but after that,Mybe I have 10000 tables in my DB. it is too much and administration is too heavy.
Is there a better way to save messages?
First , 10000 users is not so much data for mysql. In my system, I have more than 10,000,000 data in one table, and it works well.
Second, whether user and message should be stored in independent tables, this depends on the query. If you make a lot of join, I suggest You store them in one table, But if the join action is not that frequent, you can seperate them.

How to change the values of two table automatically (MySQL)?

I have a database with two tables. The first one contains the user_name, user_password, user_email. The second one contains the user_name, user_age, user_description.
When a person finds the user he needs by the user_name, the script looks through the database using the user_name, to give out the information about certain user.
But if the person changes his user_name via preferences, the value changes only in the first table.
Question:
1) Is there a way to make the user_name in the second table change automatically? (To connect them some how)
I am using MySQL (phpMyAdmin).
This is just a simple example. In "real world" I am trying to manage more serious applications that have more tables. Is there an easier way than to create a separate php query for each table?
You could always create an AFTER UPDATE MySQL trigger targeting single rows for this. See the manual. It's probably not easier than using separate PHP queries for the tables, though. You don't need to spell them all out, just map up what needs to be synchronized when, and abstract your code.
However I'd recommend that you use a unique ID field for the user and only store the username in one of the tables -- and refer to the user with the ID under the hood of your code, and in both tables. Not a good idea to use something changeable as a unique identifier in your database design.

Regex for SQL string to allow SELECT queries on variable named tables only?

The table names are variable, but what is certain is that SELECT only is allowed and certain tables are excluded (ie Users, Log). I'm making a reporting form where a user can just enter sql queries to make template reports.
SELECT 'field1' As 'foo', 'field2' as 'bar'.. 'fieldn'
FROM 'table1',..'tablen'
JOIN ... ON ...
WHERE CONDITION
Although I'm thinking I can have the table names in a html select list of existing tables.
Also make a user reporter_appname#localhost with SELECT access only to all tables except Users and Log? In that case I won't need to bother with a regex check of the query?
(This would be in PHP)
(Ideally I just wanted a single textarea where the admin can just type their query, my report function would then take the output and present it nicely etc.)
I suggest you re-think your design.
Identifying valid select statements (and excluding all other statements) is basically impossible without completely parsing SQL. A regex is not going to be up to the task.
Even if you allow only select statements, users could perform denial-of-service attacks on your database. It is very easy to create select statements that run forever (we've all done it). A malicious user could crash your site in a hurry. And even well-intentioned users might do this by accident.
It would be much better to give the users more limited options for creating reports. Let them select certain tables and columns from a list, and create the appropriate query for them.
There is probably free MySQL reporting software out there that could serve as a good starting point, though I don't have any experience with this myself.
I think that you should rethink the design of your application.
The Users and Log tables should be on one database and the tables with the data for the reports should be on another database.
If you have them all in one database already just create another database, link them and then create synonyms from one database to another only for the tables that the user can access via his queries.
The user will run his queries on the database you have just created and he will be limited to those tables that have synonyms on it.
I do not know if this would be the best option because your description of the case is relatively vague but based on the information I have this could be a solution.