用于多对多相关表优化的自定义搜索查询

问题描述 投票:0回答:1

我有两个通过多对多关系相关的表。现在,我想从表 1 中检索结果,其中表 1 中的行与表 2 中的列中的特定条件相关。 例如,如果我们有两个表:“pizza”和“toppings”,我想检索所有具有toppings“a”、“b”、“c”或“d”的披萨。

我想知道循环一次电影标题并比较标题(第一种方法)是否更快,或者多次循环并与结果 ID 相交(第二种方法)是否更快。

此外,我正在寻找具有此关系的更大数据库,我可以用它来测试性能。

请注意,我将使用 SQLite,性能主要取决于此数据库。

为了测试性能,我使用了“sqlite-salika.db”数据库(来自 Kaggle)并运行了以下代码。然而,时间差异并不能让我们深入了解哪种方法表现更好。两个查询都在 SQLite 上运行,并且表预计不会超过 10,000 行。但我想知道哪种方法通常会有更好的性能,特别是在较大的数据库中。


public static void CheckStringWithEachID(SQLiteConnection conn) {
    Stopwatch sw = new Stopwatch();
    int count = 0;

    sw.Start();
    // AND happens before OR
    using (var cmd = new SQLiteCommand(conn)) {
        cmd.CommandText = @"
            SELECT act.first_name,act.last_name, fi.title  FROM actor act
            JOIN film_actor fa ON act.actor_id = fa.actor_id
            JOIN film fi ON fa.film_id = fi.film_id
            WHERE LOWER(fi.title) LIKE LOWER('t%')
                AND LOWER(fi.title) LIKE LOWER('%r')
                OR LOWER(fi.title) LIKE LOWER('%bird%')
                OR LOWER(fi.title) LIKE LOWER('%house%')
            ";
        var reader = cmd.ExecuteReader();
        while (reader.Read()) {
            //Console.WriteLine(string.Format("{0,-12} - {1,-13} {2,-20}", reader.GetValue(0),reader.GetValue(1),reader.GetValue(2)));
            count++;
        }
    }
    sw.Stop();
    Console.WriteLine("Result query count = " + count);
    Console.WriteLine("Elapsed={0}", sw.Elapsed); //00:00:00.0539724
}
public static void CheckIfInIDs(SQLiteConnection conn) {
    Stopwatch sw = new Stopwatch();
    int count = 0;
    sw.Start();
    using (var cmd = new SQLiteCommand(conn)) {
        cmd.CommandText = @"
            SELECT act.* FROM actor act
            JOIN film_actor fa ON act.actor_id = fa.actor_id
            JOIN film fi ON fa.film_id = fi.film_id
            WHERE LOWER(fi.film_id)  IN (SELECT film_id FROM film WHERE LOWER(title) LIKE LOWER('t%'))
                AND LOWER(fi.film_id)  IN (SELECT film_id FROM film WHERE LOWER(title) LIKE LOWER('%r'))
                OR LOWER(fi.film_id)  IN (SELECT film_id FROM film WHERE LOWER(title) LIKE LOWER('%bird%'))
                OR LOWER(fi.film_id)  IN (SELECT film_id FROM film WHERE LOWER(title) LIKE LOWER('%house%'))
            ";
        var reader = cmd.ExecuteReader();
        while (reader.Read()) {
            //Console.WriteLine(string.Format("{0,-12} - {1,-13} {2,-20}", reader.GetValue(0), reader.GetValue(1), reader.GetValue(2)));
            count++;
        }
    }
    sw.Stop();
    Console.WriteLine("Result query count = " + count);
    Console.WriteLine("Elapsed={0}", sw.Elapsed);
}
static void Main(string[] args) {
    using (var conn = new SQLiteConnection("Data Source=" + "sqlite-sakila.db")){
        conn.Open();
        CheckStringWithEachID(conn); // connection first time overhead? slower for some reason
        CheckStringWithEachID(conn);
        CheckIfInIDs(conn);
        conn.Close();

    }

}

我预计会有更大且一致的时间差异,以清楚地表明哪种方法总体上更好。

代码结果(添加/更改/删除一些 OR 和 AND 条件时):

Result query count = 31
Elapsed=00:00:00.0058455
Result query count = 31
Elapsed=00:00:00.0059143

Result query count = 87
Elapsed=00:00:00.0080970
Result query count = 87
Elapsed=00:00:00.0065998

Result query count = 77
Elapsed=00:00:00.0049120
Result query count = 77
Elapsed=00:00:00.004717
optimization query-optimization database-performance
1个回答
0
投票

我发现第一个答案实际上并不像我预期的那样工作。因为它会将每个 film_title (在我的示例中)与所有这些条件进行比较,这不是预期的。 我希望参与 movie_titles 的演员至少参与了 movie_title 满足 AND 条件之一(因此第二种方式是我发现可行的两种方式之一。另一种方式未写这里是使用不同的命名多次执行多个相同的查询并更改评估值,然后将它们连接在一起)。

不幸的是,我无法链接其他查询,因为我丢失了找到它的位置。但形成它的绳子会大很多。

© www.soinside.com 2019 - 2024. All rights reserved.