Tengo una database SQLite de ~ 90 MB en un disco SSD que consiste principalmente en files adjuntos de posts, incluido un contenido de columna BLOB, que almacena los datos del file adjunto binary.
Ahora encontré que la siguiente consulta
SELECT message_id FROM attachments WHERE length(content) IS NULL;
es 500 veces más rápido (0.5ms vs. 250ms) que el original
SELECT message_id FROM attachments WHERE content IS NULL;
¿Es cierto que ambas consultas son equivalentes?
información adicional
En SQLite, la longitud y el tipo de cada valor de columna se almacenan al comienzo de la fila . Esto permite optimizar las funciones length()
y typeof()
para evitar cargar el valor real.
El operador IS NULL no tiene dicha optimization (aunque sería posible implementarla).
Hice una secuencia de commands para comparar ambas funciones. length(x) IS NULL
es más rápido a less que tenga valores NULL
su mayoría.
IS NULL
: 11.343180236999842 length(x) IS NULL
NULA: 7.824154090999855 IS NULL
: 15.019244787999924 length(x) IS NULL
NULA: 7.527420233999919 IS NULL
: 6.184766045999822 length(x) IS NULL
NULA: 6.448342310000044 import sqlite3 import timeit conn = sqlite3.connect("test.db") c = conn.cursor() c.execute("DROP TABLE IF EXISTS test") c.execute("CREATE TABLE test (data BLOB)") for i in range(10000): # Modify this to change data if i % 2 == 0: c.execute("INSERT INTO test(data) VALUES (randomblob(1024))") else: c.execute("INSERT INTO test(data) VALUES (NULL)") def timeit_isnull(): c.execute("SELECT data IS NULL AS dataisnull FROM test") c.fetchall() def timeit_lenisnull(): c.execute("SELECT length(data) IS NULL AS dataisnull FROM test") c.fetchall() print(timeit.timeit(timeit_isnull, number=1000)) print(timeit.timeit(timeit_lenisnull, number=1000))
En realidad, utilizar LENGTH(some_blob_content)
instruye al server MySQL 5.5 y superior para eludir el escaneo de filas, esta es la razón para un mejor performance de su consulta, porque los datos se leen directamente desde la tabla de metadatos.
EDITAR:
En SQLite durante el process parte INSERT
y SELECT
, el contenido completo de cada fila en la database se codifica como un solo BLOB . Mira aquí para más detalles.
También para un valor de cadena X, la function de
length(X)
devuelve el número de caracteres ( no bytes ) en X antes del primer carácterNULL
. Como las cadenas de SQLite normalmente no contienen caracteresNULL
, la function delength(X)
generalmente devolverá el número total de caracteres en la cadena X. Para un valor deblob
X, lalength(X)
devuelve el número de bytes en la burbuja. Si X esNULL
, lalength(X)
es NULL. Si X es numérico, lalength(X)
devuelve la longitud de una representación de cadena de X.
La cita anterior de la documentation sugiere que, para los valores de blob , el procedimiento de lectura de su longitud es el mismo que en MySQL, es decir, desde la tabla de metadatos.