Reputation: 327
I have a long table with stock prices that, among other fields, includes the following:
| Date | exchange_code | ticker | price |
|------------|---------------------|--------------|-------------|
|2020 -01-01 | US | GOOG | XXXXX |
I would like to know which is the most efficient way to select rows where pairs (exchange_code and ticker) are included in a given array.
The only idea I have is to add another column like exchange_ticker
and then use a query like
SELECT * FROM mytable
WHERE exchange_ticker IN (X,Y,Z);
Also, as the table is quite long, I would add an index over this column.
I'm sure there must be a better way... any idea?
Thanks!
Upvotes: 0
Views: 1163
Reputation: 33935
GL's idea is a nice one but (at least in older versions of MySQL) it's not going to help much...
mysql> EXPLAIN
-> SELECT *
-> FROM mytable
-> WHERE (exchange_code, ticker) IN ( ('US','MOBI'), ('US','TESL'), ('UK','BP') );
+----+-------------+---------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | mytable | ALL | NULL | NULL | NULL | NULL | 147 | Using where |
+----+-------------+---------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)
mysql> EXPLAIN
-> SELECT *
-> FROM mytable
-> WHERE (exchange_code = 'US' AND ticker = 'MOBI')
-> OR (exchange_code = 'US' AND ticker = 'TESL')
-> OR (exchange_code = 'UK' AND ticker = 'BP')
-> ;
+----+-------------+---------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | mytable | ALL | exchange_code | NULL | NULL | NULL | 147 | Using where |
+----+-------------+---------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)
mysql> SELECT VERSION();
+-----------+
| VERSION() |
+-----------+
| 5.6.21 |
+-----------+
The second query doesn't use the index because my data set is tiny. The first query doesn't even find the index.
If I increase the size of the data set (and the cardinality of exchange_code) slightly, the difference becomes more pronounced.
mysql> EXPLAIN
-> SELECT *
-> FROM mytable
-> WHERE (exchange_code = 'US' AND ticker = 'MOBI')
-> OR (exchange_code = 'US' AND ticker = 'TESL')
-> OR (exchange_code = 'UK' AND ticker = 'BP')
-> ;
+----+-------------+---------+-------+---------------+---------------+---------+------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+-------+---------------+---------------+---------+------+------+-----------------------+
| 1 | SIMPLE | mytable | range | exchange_code | exchange_code | 16 | NULL | 43 | Using index condition |
+----+-------------+---------+-------+---------------+---------------+---------+------+------+-----------------------+
1 row in set (0.00 sec)
mysql> EXPLAIN
-> SELECT *
-> FROM mytable
-> WHERE (exchange_code, ticker) IN ( ('US','MOBI'), ('US','TESL'), ('UK','BP') );
+----+-------------+---------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | mytable | ALL | NULL | NULL | NULL | NULL | 2352 | Using where |
+----+-------------+---------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)
Upvotes: 0
Reputation: 1269683
You can use tuples:
SELECT *
FROM mytable
WHERE (exchange, ticker) IN ( (A, X), (B, Y), (C, Z) );
This should be able to take advantage of an index on mytable(exchange, ticker)
.
If the list is already in a table, you can use JOIN
:
select t.*
fro mytable t join
list l
using (exchange, ticker);
You also want an index for this as well.
Upvotes: 2