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 false /* is_set_id */});
31 schema.columns.push_back({"type", SqlValue::Type::kLong, false /* is_id */,
32 false /* is_sorted */, false /* is_hidden */,
33 false /* is_set_id */});
34 schema.columns.push_back({"test1", SqlValue::Type::kLong, false /* is_id */,
35 true /* is_sorted */, false /* is_hidden */,
36 false /* is_set_id */});
37 schema.columns.push_back({"test2", SqlValue::Type::kLong, false /* is_id */,
38 false /* is_sorted */, false /* is_hidden */,
39 false /* is_set_id */});
40 schema.columns.push_back({"test3", SqlValue::Type::kLong, false /* is_id */,
41 false /* is_sorted */, false /* is_hidden */,
42 false /* is_set_id */});
43 return schema;
44 }
45
TEST(DbSqliteTable,IdEqCheaperThanOtherEq)46 TEST(DbSqliteTable, IdEqCheaperThanOtherEq) {
47 auto schema = CreateSchema();
48 constexpr uint32_t kRowCount = 1234;
49
50 QueryConstraints id_eq;
51 id_eq.AddConstraint(0u, SQLITE_INDEX_CONSTRAINT_EQ, 0u);
52
53 auto id_cost = DbSqliteTable::EstimateCost(schema, kRowCount, id_eq);
54
55 QueryConstraints a_eq;
56 a_eq.AddConstraint(1u, SQLITE_INDEX_CONSTRAINT_EQ, 1u);
57
58 auto a_cost = DbSqliteTable::EstimateCost(schema, kRowCount, a_eq);
59
60 ASSERT_LT(id_cost.cost, a_cost.cost);
61 ASSERT_LT(id_cost.rows, a_cost.rows);
62 }
63
TEST(DbSqliteTable,IdEqCheaperThatOtherConstraint)64 TEST(DbSqliteTable, IdEqCheaperThatOtherConstraint) {
65 auto schema = CreateSchema();
66 constexpr uint32_t kRowCount = 1234;
67
68 QueryConstraints id_eq;
69 id_eq.AddConstraint(0u, SQLITE_INDEX_CONSTRAINT_EQ, 0u);
70
71 auto id_cost = DbSqliteTable::EstimateCost(schema, kRowCount, id_eq);
72
73 QueryConstraints a_eq;
74 a_eq.AddConstraint(1u, SQLITE_INDEX_CONSTRAINT_LT, 1u);
75
76 auto a_cost = DbSqliteTable::EstimateCost(schema, kRowCount, a_eq);
77
78 ASSERT_LT(id_cost.cost, a_cost.cost);
79 ASSERT_LT(id_cost.rows, a_cost.rows);
80 }
81
TEST(DbSqliteTable,SingleEqCheaperThanMultipleConstraint)82 TEST(DbSqliteTable, SingleEqCheaperThanMultipleConstraint) {
83 auto schema = CreateSchema();
84 constexpr uint32_t kRowCount = 1234;
85
86 QueryConstraints single_eq;
87 single_eq.AddConstraint(1u, SQLITE_INDEX_CONSTRAINT_EQ, 0u);
88
89 auto single_cost = DbSqliteTable::EstimateCost(schema, kRowCount, single_eq);
90
91 QueryConstraints multi_eq;
92 multi_eq.AddConstraint(1u, SQLITE_INDEX_CONSTRAINT_EQ, 0u);
93 multi_eq.AddConstraint(2u, SQLITE_INDEX_CONSTRAINT_EQ, 1u);
94
95 auto multi_cost = DbSqliteTable::EstimateCost(schema, kRowCount, multi_eq);
96
97 // The cost of the single filter should be cheaper (because of our special
98 // handling of single equality). But the number of rows should be greater.
99 ASSERT_LT(single_cost.cost, multi_cost.cost);
100 ASSERT_GT(single_cost.rows, multi_cost.rows);
101 }
102
TEST(DbSqliteTable,MultiSortedEqCheaperThanMultiUnsortedEq)103 TEST(DbSqliteTable, MultiSortedEqCheaperThanMultiUnsortedEq) {
104 auto schema = CreateSchema();
105 constexpr uint32_t kRowCount = 1234;
106
107 QueryConstraints sorted_eq;
108 sorted_eq.AddConstraint(2u, SQLITE_INDEX_CONSTRAINT_EQ, 0u);
109 sorted_eq.AddConstraint(3u, SQLITE_INDEX_CONSTRAINT_EQ, 0u);
110
111 auto sorted_cost = DbSqliteTable::EstimateCost(schema, kRowCount, sorted_eq);
112
113 QueryConstraints unsorted_eq;
114 unsorted_eq.AddConstraint(3u, SQLITE_INDEX_CONSTRAINT_EQ, 0u);
115 unsorted_eq.AddConstraint(4u, SQLITE_INDEX_CONSTRAINT_EQ, 0u);
116
117 auto unsorted_cost =
118 DbSqliteTable::EstimateCost(schema, kRowCount, unsorted_eq);
119
120 // The number of rows should be the same but the cost of the sorted
121 // query should be less.
122 ASSERT_LT(sorted_cost.cost, unsorted_cost.cost);
123 ASSERT_EQ(sorted_cost.rows, unsorted_cost.rows);
124 }
125
TEST(DbSqliteTable,EmptyTableCosting)126 TEST(DbSqliteTable, EmptyTableCosting) {
127 auto schema = CreateSchema();
128
129 QueryConstraints id_eq;
130 id_eq.AddConstraint(0u, SQLITE_INDEX_CONSTRAINT_EQ, 0u);
131
132 auto id_cost = DbSqliteTable::EstimateCost(schema, 0, id_eq);
133
134 QueryConstraints a_eq;
135 a_eq.AddConstraint(1u, SQLITE_INDEX_CONSTRAINT_LT, 1u);
136
137 auto a_cost = DbSqliteTable::EstimateCost(schema, 0, a_eq);
138
139 ASSERT_DOUBLE_EQ(id_cost.cost, a_cost.cost);
140 ASSERT_EQ(id_cost.rows, a_cost.rows);
141 }
142
TEST(DbSqliteTable,OrderByOnSortedCheaper)143 TEST(DbSqliteTable, OrderByOnSortedCheaper) {
144 auto schema = CreateSchema();
145 constexpr uint32_t kRowCount = 1234;
146
147 QueryConstraints a_qc;
148 a_qc.AddOrderBy(1u, false);
149
150 auto a_cost = DbSqliteTable::EstimateCost(schema, kRowCount, a_qc);
151
152 // On an ordered column, the constraint for sorting would get pruned so
153 // we would end up with an empty constraint set.
154 QueryConstraints sorted_qc;
155 auto sorted_cost = DbSqliteTable::EstimateCost(schema, kRowCount, sorted_qc);
156
157 ASSERT_LT(sorted_cost.cost, a_cost.cost);
158 ASSERT_EQ(sorted_cost.rows, a_cost.rows);
159 }
160
161 } // namespace
162 } // namespace trace_processor
163 } // namespace perfetto
164