1
2 /*
3 * Copyright (C) 2019 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #include "src/trace_processor/sqlite/db_sqlite_table.h"
19
20 #include "test/gtest_and_gmock.h"
21
22 namespace perfetto {
23 namespace trace_processor {
24 namespace {
25
CreateSchema()26 Table::Schema CreateSchema() {
27 Table::Schema schema;
28 schema.columns.push_back({"id", SqlValue::Type::kLong, true /* is_id */,
29 true /* is_sorted */, false /* is_hidden */});
30 schema.columns.push_back({"type", SqlValue::Type::kLong, false /* is_id */,
31 false /* is_sorted */, false /* is_hidden */});
32 schema.columns.push_back({"test1", SqlValue::Type::kLong, false /* is_id */,
33 true /* is_sorted */, false /* is_hidden */});
34 schema.columns.push_back({"test2", SqlValue::Type::kLong, false /* is_id */,
35 false /* is_sorted */, false /* is_hidden */});
36 schema.columns.push_back({"test3", SqlValue::Type::kLong, false /* is_id */,
37 false /* is_sorted */, false /* is_hidden */});
38 return schema;
39 }
40
TEST(DbSqliteTable,IdEqCheaperThanOtherEq)41 TEST(DbSqliteTable, IdEqCheaperThanOtherEq) {
42 auto schema = CreateSchema();
43 constexpr uint32_t kRowCount = 1234;
44
45 QueryConstraints id_eq;
46 id_eq.AddConstraint(0u, SQLITE_INDEX_CONSTRAINT_EQ, 0u);
47
48 auto id_cost = DbSqliteTable::EstimateCost(schema, kRowCount, id_eq);
49
50 QueryConstraints a_eq;
51 a_eq.AddConstraint(1u, SQLITE_INDEX_CONSTRAINT_EQ, 1u);
52
53 auto a_cost = DbSqliteTable::EstimateCost(schema, kRowCount, a_eq);
54
55 ASSERT_LT(id_cost.cost, a_cost.cost);
56 ASSERT_LT(id_cost.rows, a_cost.rows);
57 }
58
TEST(DbSqliteTable,IdEqCheaperThatOtherConstraint)59 TEST(DbSqliteTable, IdEqCheaperThatOtherConstraint) {
60 auto schema = CreateSchema();
61 constexpr uint32_t kRowCount = 1234;
62
63 QueryConstraints id_eq;
64 id_eq.AddConstraint(0u, SQLITE_INDEX_CONSTRAINT_EQ, 0u);
65
66 auto id_cost = DbSqliteTable::EstimateCost(schema, kRowCount, id_eq);
67
68 QueryConstraints a_eq;
69 a_eq.AddConstraint(1u, SQLITE_INDEX_CONSTRAINT_LT, 1u);
70
71 auto a_cost = DbSqliteTable::EstimateCost(schema, kRowCount, a_eq);
72
73 ASSERT_LT(id_cost.cost, a_cost.cost);
74 ASSERT_LT(id_cost.rows, a_cost.rows);
75 }
76
TEST(DbSqliteTable,SingleEqCheaperThanMultipleConstraint)77 TEST(DbSqliteTable, SingleEqCheaperThanMultipleConstraint) {
78 auto schema = CreateSchema();
79 constexpr uint32_t kRowCount = 1234;
80
81 QueryConstraints single_eq;
82 single_eq.AddConstraint(1u, SQLITE_INDEX_CONSTRAINT_EQ, 0u);
83
84 auto single_cost = DbSqliteTable::EstimateCost(schema, kRowCount, single_eq);
85
86 QueryConstraints multi_eq;
87 multi_eq.AddConstraint(1u, SQLITE_INDEX_CONSTRAINT_EQ, 0u);
88 multi_eq.AddConstraint(2u, SQLITE_INDEX_CONSTRAINT_EQ, 1u);
89
90 auto multi_cost = DbSqliteTable::EstimateCost(schema, kRowCount, multi_eq);
91
92 // The cost of the single filter should be cheaper (because of our special
93 // handling of single equality). But the number of rows should be greater.
94 ASSERT_LT(single_cost.cost, multi_cost.cost);
95 ASSERT_GT(single_cost.rows, multi_cost.rows);
96 }
97
TEST(DbSqliteTable,MultiSortedEqCheaperThanMultiUnsortedEq)98 TEST(DbSqliteTable, MultiSortedEqCheaperThanMultiUnsortedEq) {
99 auto schema = CreateSchema();
100 constexpr uint32_t kRowCount = 1234;
101
102 QueryConstraints sorted_eq;
103 sorted_eq.AddConstraint(2u, SQLITE_INDEX_CONSTRAINT_EQ, 0u);
104 sorted_eq.AddConstraint(3u, SQLITE_INDEX_CONSTRAINT_EQ, 0u);
105
106 auto sorted_cost = DbSqliteTable::EstimateCost(schema, kRowCount, sorted_eq);
107
108 QueryConstraints unsorted_eq;
109 unsorted_eq.AddConstraint(3u, SQLITE_INDEX_CONSTRAINT_EQ, 0u);
110 unsorted_eq.AddConstraint(4u, SQLITE_INDEX_CONSTRAINT_EQ, 0u);
111
112 auto unsorted_cost =
113 DbSqliteTable::EstimateCost(schema, kRowCount, unsorted_eq);
114
115 // The number of rows should be the same but the cost of the sorted
116 // query should be less.
117 ASSERT_LT(sorted_cost.cost, unsorted_cost.cost);
118 ASSERT_EQ(sorted_cost.rows, unsorted_cost.rows);
119 }
120
TEST(DbSqliteTable,EmptyTableCosting)121 TEST(DbSqliteTable, EmptyTableCosting) {
122 auto schema = CreateSchema();
123
124 QueryConstraints id_eq;
125 id_eq.AddConstraint(0u, SQLITE_INDEX_CONSTRAINT_EQ, 0u);
126
127 auto id_cost = DbSqliteTable::EstimateCost(schema, 0, id_eq);
128
129 QueryConstraints a_eq;
130 a_eq.AddConstraint(1u, SQLITE_INDEX_CONSTRAINT_LT, 1u);
131
132 auto a_cost = DbSqliteTable::EstimateCost(schema, 0, a_eq);
133
134 ASSERT_DOUBLE_EQ(id_cost.cost, a_cost.cost);
135 ASSERT_EQ(id_cost.rows, a_cost.rows);
136 }
137
TEST(DbSqliteTable,OrderByOnSortedCheaper)138 TEST(DbSqliteTable, OrderByOnSortedCheaper) {
139 auto schema = CreateSchema();
140 constexpr uint32_t kRowCount = 1234;
141
142 QueryConstraints a_qc;
143 a_qc.AddOrderBy(1u, false);
144
145 auto a_cost = DbSqliteTable::EstimateCost(schema, kRowCount, a_qc);
146
147 // On an ordered column, the constraint for sorting would get pruned so
148 // we would end up with an empty constraint set.
149 QueryConstraints sorted_qc;
150 auto sorted_cost = DbSqliteTable::EstimateCost(schema, kRowCount, sorted_qc);
151
152 ASSERT_LT(sorted_cost.cost, a_cost.cost);
153 ASSERT_EQ(sorted_cost.rows, a_cost.rows);
154 }
155
156 } // namespace
157 } // namespace trace_processor
158 } // namespace perfetto
159