SA-MP Forums Archive
[Tutorial] When to use the different MySQL queries - Printable Version

+- SA-MP Forums Archive (https://sampforum.blast.hk)
+-- Forum: SA-MP Scripting and Plugins (https://sampforum.blast.hk/forumdisplay.php?fid=8)
+--- Forum: Scripting Help (https://sampforum.blast.hk/forumdisplay.php?fid=12)
+---- Forum: Tutorials (https://sampforum.blast.hk/forumdisplay.php?fid=70)
+---- Thread: [Tutorial] When to use the different MySQL queries (/showthread.php?tid=647850)



When to use the different MySQL queries - RIDE2DAY - 12.01.2018

When to use the different MySQL queries
[*] Index [*] Introduction
Hello guys, this is the second part of my MySQL tutorial series I'm writing and at the same time it's the second one I write in English, so just like I say always: if you find any grammatical error let me know please. If you read the first part you should know that I'm using the R41-4 version, if you didn't I invite you to in order to know how to establish a connection correctly. In this tutorial we're going to see what type of queries we can use and in which cases we should use each one. Before anything I'd like to let you know that I'm not a MySQL expert, so if you know better code techniques you're welcome to share them with us.


[*] MySQL queries
So, what is a query? Well, a dictionary might help you with that! Alright, jokes apart, a query basically is a "question" we send to the database in order to receive an "answer", also known as "result". The result contains the answer to our query, so that's what we process when the MySQL server returns it. With the current MySQL plugin we can send different types of queries, by different types I mean how they will be executed/treated by the SA-MP server. Here's where threaded and non-threaded queries come in.


[*] Threaded and non-threaded queries
In SA-MP the script runs on a single thread, that means that if you execute two functions consecutively the second one will run after the first one finishes, but what would happen if the first function requires a lot of time? You can read more about it on this tutorial wrote by Slice.

In short, threaded queries have been created in order to avoid unnecessary waits. Multithreading is something very useful because we can't predict the time a query requires. If the server sleeps too much we can get into desynchronization troubles. Let's see a little graphic explanation, the black line represents the SA-MP script while the green one the MySQL query:

Non-threaded query: the SA-MP script sleeps while the MySQL query is being processed.Threaded query: the SA-MP script runs while the MySQL query is being processed.
Personally, I love threaded queries. I didn't use non-threaded queries in my racing gamemode yet.


[*] What function should I use to send a query?
As I said before, with the current plugin we can send different types of queries. Let's see what we got:So, which one should we use? Well, it depends mainly on what your script does. Let's see some examples: [*] MySQL transactions
The current plugin supports MySQL transactions but they cannot be used with all the functions we've been talking about before, only mysql_tquery supports them. Let's analyze a hypothetical case: suppose you're leaving a mod garage with your tuned Elegy, how do you save its components? Well, before anything you must create a table to add them to. Table's structure should look something like this:
PHP Code:
CREATE TABLE IF NOT EXISTS `vehicle_mods` (
  `
vehicleidmediumint(11NOT NULL,
  `
slottinyint(4NOT NULL,
  `
componentidsmallint(6NOT NULL,
  
UNIQUE KEY `vehicleid` (`vehicleid`,`slot`),
  
FOREIGN KEY (`vehicleid`) REFERENCES `vehicle_info`(`id`) ON DELETE CASCADE ON UPDATE CASCADE
ENGINE=InnoDB DEFAULT CHARSET=latin1;
/* vehicleid is the SQL ID of the vehicle which we've saved inside the vehicle_info table. */ 
Now we have to loop through vehicle's mod slots to check if they containt any component:
PHP Code:
public OnEnterExitModShop(playeridenterexitinteriorid)
{
    if(!
enterexit)
    {
        new 
componentid;
        for(new 
014i++)
        {
            
componentid GetVehicleComponentInSlot(GetPlayerVehicleID(playerid), i);
            if(
componentid != 0)
            {
                
// Send save query here.
            
}
        }
    }
    return 
1;

So how should the query look? Does the execution order matter? It doesn't. Well, then this should do the job:
PHP Code:
mysql_format(db_handlequerysizeof(query),
    
"INSERT INTO `vehicle_mods` VALUES(%d, %d, %d) ON DUPLICATE KEY UPDATE `componentid` = %d;",
    
v_Info[idx][SQLID],
    
i,
    
componentid,
    
componentid
);
mysql_pquery(db_handlequery); // Notice we're using mysql_pquery. 
That works fine. If the mods use all 14 slots then 14 queries are sent, we don't know which one finishes first but it doesn't care. Keep in mind that if the POOL_SIZE is set to two only two run at once, then another two and so on. You might set the POOL_SIZE to 14 to run all them at once.

That technique isn't bad at all, it works, but we can do it better: MySQL transactions. This would be even faster:
PHP Code:
mysql_tquery(db_handle"START TRANSACTION;"); // Start transaction.
for(new 014i++)
{
    
componentid GetVehicleComponentInSlot(GetPlayerVehicleID(playerid), i);
    if(
componentid != 0)
    {
        
mysql_format(db_handlequerysizeof(query),
            
"INSERT INTO `vehicle_mods` VALUES(%d, %d, %d) ON DUPLICATE KEY UPDATE `componentid` = %d;",
            
v_Info[idx][SQLID],
            
i,
            
componentid,
            
componentid
        
);
        
mysql_tquery(db_handlequery); // Notice we're using mysql_tquery.
    
}
}
mysql_tquery(db_handle"COMMIT;"); // Commit transaction. 
A transaction supports different statements, you don't have to run only SELECT, INSERT, etc. statements inside but whatever you want. This isn't a SQL tutorial, I'm trying to document plugin's functions but here you have a little example just to make you understand what I mean:
PHP Code:
mysql_tquery(db_handle"START TRANSACTION;");
mysql_tquery(db_handle"SELECT * FROM ...", ...);
mysql_tquery(db_handle"INSERT INTO ...", ...);
mysql_tquery(db_handle"UPDATE ...", ...);
mysql_tquery(db_handle"COMMIT;"); 
[*] mysql_format or format?
Many people asked me about this, it's really easy: mysql_format uses the charset you've set with mysql_set_charset, if I'm not wrong by default it's set to utf8. I'm not really sure about which charset uses SA-MP's format function but I think it's utf8 also.

So, supposing both use the same charset by default, why would I use mysql_format? It has special format specifiers, like %e, which escapes strings automatically instead of using mysql_escape_string. Check the documentation to see what other specifiers it supports.


[*] How to create a table correctly
As I told you before, we should make sure our tables have been created before using SELECT statements. Currently we can run SQL statements written in external files using:It doesn't care if we send a non-threaded query in OnGameModeInit, it'll run only once, so doing something like this works fine:
PHP Code:
public OnGameModeInit()
{
    
mysql_query_file(db_handle"my_tables.sql");
    
LoadGarages(); // SELECT statement inside.
    
return 1;

That's just an example, but it would work.


[*] The end
This is where the second tutorial finishes, on the next one we're going to see how to make a login/register system using Whirlpool hashes. You might follow the development of the MySQL gamemode I'm writing for these tutorials on GitHub, that way you could see and understand better what I do.

Thank you for reading my thread, if you want to support what I do you might buy me a coffe! Subscribe to my ******* channel if you wish to follow the development of my gamemode.

Please, if you find any error let me know so I can correct it.

Arrivederci!


Re: When to use the different MySQL queries - Eoussama - 12.01.2018

Splendid, learned a thing or two, thanks for your effort, I hope you cover some salting methods on the next tutorial too.


Re: When to use the different MySQL queries - Logic_ - 13.01.2018

I'm out of words to explain about the tutorial. Beautifully and amazingly done with usage of good vocabulary that I know about but never used xD.

One of the errors that I noticed are that you did not mention which image represents what (a threaded query or a non threaded) @ Threaded and non-threaded queries. I also at first sight got confused but since I know how MySQL works, I understood it. But to a completely new person who is trying to learn or improve their skills would get stuck!


Re: When to use the different MySQL queries - Virtual1ty - 13.01.2018

Beautifully written tutorial. Great explaining. I'll for sure be checking it when porting my script(s) that use the old version(R7) of the MySQL plugin.


Re: When to use the different MySQL queries - Kaperstone - 13.01.2018

Finally a tutorial I can link people to when they use mysql_query


I haven't read the tutorial but from the looks of it seems well detailed.


Re: When to use the different MySQL queries - Logic_ - 11.04.2018

Sorry for the bump but there are two reasons behind it:
  1. It's a very good tutorial and almost everyone who uses MySQL should read this.
  2. Secondly, can you make a tutorial based on the database relations? The one by Vince is good too but it's kind of outdated and your explanation is better (or that's what I've felt!)