All major database applications (including MySQL and MariaDB) now support recursive queries using common table expressions. This was introduced in MySQL version 8.0 and MariaDB version 10.2.2. PostgreSQL had support even earlier. Oracle has this, and SQL Server added this with the 2005 version. In fact, a quick search reveals that Sqlite also supports Common Table Expressions.
Therefore, the answer you can look for is to use common table expressions and recursive queries. This explains some of the reasons why this is considered a better solution compared to the " Representation Model of Directional Acyclic Graphs (DAG) in SQL Databases ":
Coding and querying graphs in a relational model
https://drtom.ch/posts/2012/02/11/Encoding_and_Querying_Graphs_in_the_Relational_Model/
(You can ignore the part where he says: “This will not work, particularly on MySQL or sqlite3, which simply do not support CTE.” As I said, this is no longer the case.)
As you noted in your question, "when I use this method, there will be millions of data in this table." This in itself may not be so bad if you exchanged space for efficiency everywhere, but as Dr. Tom Post explains in one example:
The operation of removing or inserting a red arc also requires effort in θ (n ^ 2).
This is an n-square force for these operations; You get query efficiency, but at the expense of space inefficiency and insertion / deletion inefficiencies. He goes on to point out that
almost all major real-world networks are rare. They have much fewer edges than would be possible, i.e. M "n ^ 2.
In fairness, the Cam Erdogan article you linked was written in 2008; CTEs were not public then. In addition, Erdogan made an informed choice regarding compromise, as he explained here:
The solution I have is based on recursion [too]. However, instead of deferring recursion until the request time, I do recursion during insertion, assuming that the graph is actually more requested than modified (which is true for all the cases that I have encountered so far).
If, after reading Dr. Tom’s article, you ultimately prefer Erdogan’s compromises, you can limit other inefficiencies by looking at the Laravel implementation here:
GitHub - telkins / laravel-dag-manager: SQL-based directed acyclic graph (DAG) solution for Laravel. https://github.com/telkins/laravel-dag-manager
In particular, look at Max Hops and implement something similar in your own solution.
This is in the Laravel configuration file:
'max_hops' => 5,
Disclaimer: I am only now investigating this for myself. I have no experience using any of these solutions yet.