Reducing Online Serving Latency from 1.11s to 123.6ms
ossinsight.io
ossinsight.io
For example, if you have a database of people with their first and last names, and let's say there are 1000 distinct first names and 100,000 distinct last names, you'd want the index to by (last, first) no? You're saying the opposite?
edit: Here a quote from Percona as well: "In the simplest case, we want to put the most selective column first in the index, so that the number of possible matching rows is the smallest, i.e. we find the rows as quickly as possible." - https://www.percona.com/blog/2009/06/05/a-rule-of-thumb-for-...
CREATE TABLE a/b
(
x int,
y int,
z int,
)
CREATE INDEX a ON a (x, y, z)
CREATE INDEX b ON b (z, y, x) # index in reverse order
Some pseudocode to illustrate how I filled the tables: for x = 1 to 10:
for y = 1 to 1000:
for z = 1 to 10000:
INSERT INTO a/b VALUES (x, y, z)
Table a took 25 minutes and 2 seconds to populate with 100 million rows.Table b took 37 hours and 40 minutes to populate. Something's up. I built table a a second time, again taking pretty much the same 25 minutes, and I tried building table b again as well but gave up after four hours. It's definitely not the computer acting up, nor the storage.
+--------+------------+
| Table | Checksum |
+--------+------------+
| test.a | 4243132544 |
| test.b | 4243132544 |
+--------+------------+
Not the data either. Both tables checksum identically. Here's what the storage looks like: -rw-rw---- 1 mysql mysql 6618611712 Jan 15 15:42 a.ibd
-rw-rw---- 1 mysql mysql 8715763712 Jan 16 17:42 b.ibd
+------------+-----------+-----------+
| table_name | data_mb | index_mb |
+------------+-----------+-----------+
| a | 3478.0000 | 2132.0000 |
| b | 3769.0000 | 4290.7344 |
+------------+-----------+-----------+
So the index of table b is obviously a horrendous crow's nest. It's twice as large as the index of table a, and it's even occupying more space than the actual rows themselves. I ran 100k reproducible queries on each of the tables to see how the composite indices perform. More wonky pseudocode: srand ( 1234567 )
for i = 1 to 100000:
# this includes 0 which is intentional
xr = prng ( 0 to 10 )
yr = prng ( 0 to 1000 )
zr = prng ( 0 to 10000 )
SELECT * FROM a/b WHERE x = xr AND y = yr AND z = zr
table a
=======
42 seconds
48 seconds
35 seconds
table b
=======
87 seconds
71 seconds
69 seconds
Some caching is of course involved. I queried the tables one after another just to see if rattling the cage a bit would have any effect: table a: 48 seconds
table b: 83 seconds
table a: 61 seconds
table b: 72 seconds
A little bit, but nowhere near enough to outperform the lean and correctly built index on table a. And this is just a simple three-column composite index - the problem I'm illustrating grows exponentially with every column you add to the composite.Needless to say, the database servers absolutely hate this application. Because queries are completely dynamic based on filters there's no way to index things, so full table scans are not uncommon (we've at least got some conditional indexes to filter active accounts out from inactive ones to limit the most common queries to just those accounts that haven't been paid down).
So yeah, database servers hate these kinds of workloads, and not much you can do to make them happy :/