Cómo ejecuta Salesforce una consulta
También en 19 idiomas
English · Español · 日本語 · Português (Brasil) · Français · Deutsch · Italiano · 한국어 · 简体中文 · Português (Portugal) · 繁體中文 · Bahasa Indonesia · Türkçe · Polski · Tiếng Việt · ไทย · Українська · Français (Canada) · Deutsch (Schweiz)

Módulo 4 de 5 del capítulo Arquitectura de consultas y recuperación, capítulo 8 del curso Data Architect. Cada módulo se sostiene por sí solo. Anterior: Cuándo usa Salesforce un índice · Siguiente: Buscar no es consultar
La pregunta que responde este módulo: ¿quién decide cómo ejecuta Salesforce tu consulta, y cómo elige?
En el módulo anterior, tenían que cumplirse tres cosas para que se disparara el nitro: un índice, una forma selectiva de preguntar y no demasiadas coincidencias. Entonces, ¿quién comprueba las tres cada vez que se ejecuta una consulta? Lo conoceremos en un minuto. Primero, cuatro palabras, porque así es como piensa.
Cuatro palabras que conviene conocer
Sección titulada «Cuatro palabras que conviene conocer »En este punto de la clase escribo cuatro palabras en la pizarra, porque las usaremos el resto del capítulo:
- Consulta (query): encontrar los registros que pediste. La búsqueda.
- Recuperación (fetch): traer los campos de esos registros. Una vez que has encontrado los libros, ¿cuánto te llevas de vuelta: un campo o cien?
- Recorrido de la tabla (table scan): tocar todos los registros para encontrar los que quieres. En la biblioteca, es recorrer todos los pasillos y abrir todos los libros, como en la pregunta de Harbor Press del módulo anterior, donde no había cajón por editorial. Rápido con cien registros, lento con 50 millones.
- Unión (join): pasar de un objeto a otro. Recuerda la unión que nunca escribiste, en el módulo 1.
Toda solicitud hace las dos primeras: encontrar los registros y luego llevarlos de vuelta. Son costes distintos, y ayuda mantenerlos separados. La consulta trata de qué registros: ¿son 12 o 12 millones? La recuperación trata de cuánto te llevas de vuelta: el número de registros por el número de campos. Mil registros con cinco campos es una carga ligera. Un millón de registros con cien campos es un camión. Un índice ayuda a la consulta, a encontrar. No hace pequeña una recuperación grande. Los recorridos de la tabla y las uniones son los caros. Una consulta rápida encuentra pocos registros enseguida y recupera solo los campos que necesita.
El bibliotecario es el optimizador de consultas
Sección titulada «El bibliotecario es el optimizador de consultas »Si entraras en una biblioteca y pidieras un libro, ¿con quién hablarías? Con el bibliotecario. Salesforce también tiene un bibliotecario. ¿Cómo se llama? El optimizador de consultas (query optimizer).
Cuando llega tu consulta, el bibliotecario no corre directo a las estanterías. Salesforce describe los pasos: “Primero, la plataforma ejecuta ‘preconsultas’ que tienen en cuenta las estadísticas adaptadas al entorno multiinquilino. Luego, según los resultados que devuelven las preconsultas, el servicio construye la consulta de base de datos subyacente óptima para ejecutarla” (Platform Multitenant Architecture (se abre en una pestaña nueva)). En términos de biblioteca, el bibliotecario comprueba primero: ¿cuántos libros es probable que coincidan? ¿Hay un cajón para esto? ¿Y quién pregunta? Un responsable que puede ver todos los registros y un vendedor que solo ve los suyos reciben planes distintos, porque la plataforma mantiene estadísticas para “usuarios con mucha visibilidad (un responsable que puede ver todas las filas) frente a usuarios con poca visibilidad (vendedores que solo pueden ver las filas relacionadas con ellos)” (misma fuente).
Luego el bibliotecario decide. “Todos los libros cuyo título empieza por ‘Fontanería’”: hay un cajón de títulos, así que lo usa. “Todos los libros publicados después de 1950”: cumplen la condición nueve millones de los 10 millones de libros. ¿Debería el bibliotecario consultar 9 millones de fichas y luego traer 9 millones de libros? En algún momento el atajo deja de ser un atajo, y el bibliotecario decide recorrer las estanterías sin más. Que un índice exista no garantiza que Salesforce lo vaya a usar. Esa decisión le corresponde al optimizador de consultas (Query Optimizer (se abre en una pestaña nueva)).
Esta es la descripción completa de su trabajo, en palabras de Salesforce. El optimizador de consultas trabaja sobre las consultas que hay detrás de “informes, vistas de lista y consultas SOQL”, y:
- “Determina el mejor índice desde el que dirigir la consulta, si es posible, según los filtros de la consulta”
- “Determina la mejor tabla desde la que dirigir la consulta, si no hay ningún índice bueno disponible”
- “Determina cómo ordenar las tablas restantes para minimizar el coste”
- “Inserta las tablas de valores de claves externas personalizadas necesarias para crear rutas de unión eficientes”
- “Influye en el plan de ejecución de las uniones restantes, incluidas las uniones de uso compartido, para minimizar la entrada y salida (E/S) de la base de datos”
- “Actualiza las estadísticas”
(Lightning Platform Query Optimizer (se abre en una pestaña nueva), Best Practices for Deployments with Large Data Volumes, Winter ‘27.) Busca las cuatro palabras en esa lista. Dirigir desde un índice, o desde la tabla cuando no hay ningún índice bueno disponible, decide si la consulta es una búsqueda rápida o un recorrido de la tabla. Ordenar las tablas y construir las rutas de unión tiene que ver con las uniones, incluida la unión oculta del uso compartido. Y solo cuando se han encontrado los registros, la recuperación trae de vuelta sus campos.
Así que sigue a una consulta en su recorrido. Llega. El bibliotecario comprueba lo que sabe: cuántos registros, cómo se reparten, quién pregunta. Luego toma los filtros de uno en uno y pasa cada uno por las tres comprobaciones del módulo anterior, el nitro:
- ¿Está indexado el campo? Un índice estándar, o uno personalizado.
- ¿Se pregunta de forma selectiva? Igual a, empieza por, una lista corta, un rango de fechas o números. No contiene, termina en, distinto de ni vacío.
- ¿Hay pocas coincidencias? Por debajo del umbral de selectividad para ese tipo de índice: el 30 % del primer millón de registros para un índice estándar, el 10 % para uno personalizado, con sus topes.
Cada filtro se juzga por sí solo. Un filtro que pasa las tres puede convertirse en la vía de entrada, y la consulta empieza desde ese índice. Luego vienen las uniones con cualquier otro objeto y, por último, la recuperación de los campos que pediste. Si ningún filtro pasa, el bibliotecario recorre las estanterías: un recorrido de la tabla.
El bibliotecario comprueba antes de ponerse a caminar.
Tú escribes la consulta. El bibliotecario decide cómo se ejecuta.
Conocimiento para el examen. El optimizador de consultas de Lightning Platform decide cómo se ejecutan todas las consultas, informes y vistas de lista. Ejecuta preconsultas contra sus estadísticas, juzga cada filtro (si el campo está indexado, si se pregunta de forma selectiva, si las coincidencias están por debajo del umbral), dirige la consulta desde el mejor índice, o desde la tabla cuando no hay ningún índice bueno disponible, y ordena las uniones. La misma consulta puede recibir un plan distinto para un usuario que ve todos los registros y para uno que solo ve los suyos.
¿Cuándo trabaja el bibliotecario? Todo el tiempo
Sección titulada «¿Cuándo trabaja el bibliotecario? Todo el tiempo »Entonces, ¿cuándo usas el optimizador de consultas? Lo pregunto en clase, y la mayoría responde: cuando un desarrollador escribe SOQL. La respuesta es siempre. Cada vista de lista. Cada informe con un filtro. Cada panel construido sobre esos informes. Salesforce lo dice: el optimizador “trabaja sobre las consultas generadas automáticamente que gestionan informes, vistas de lista y consultas SOQL. El optimizador también gestiona otras consultas que dependen de estas consultas generadas” (Lightning Platform Query Optimizer (se abre en una pestaña nueva), Winter ‘27).
Por eso las comprobaciones del nitro del módulo anterior importan mucho más allá del código. Una consulta ineficiente no tiene por qué escribirla un desarrollador. Puede montarla con unos clics cualquiera que construya una vista de lista o un informe:
- Una vista de lista sobre 9 millones de órdenes de trabajo con el filtro Status distinto de Completed. Un operador negativo: el índice de Status no puede ayudar, sea cual sea el volumen.
- Un filtro de informe Account Name contiene “Plumbing”. Un comodín inicial, escondido detrás de una palabra amable.
- Un tipo de informe que une órdenes de trabajo con partidas y con cuentas. Cada objeto que cruza es otra unión que el bibliotecario tiene que planificar.
Nadie escribió una línea de código, y cada una de ellas pasa por el mismo bibliotecario con las mismas tres comprobaciones. Están escondidas en lugares inofensivos: la vista de lista que un equipo abre cincuenta veces al día, el informe que hay detrás del panel del responsable. A menudo la solución es simplemente una pregunta mejor. Status igual a Scheduled o In Progress, una lista corta de valores, pregunta lo mismo de una manera que el índice puede usar.
Y también puedes preguntarle al bibliotecario por estas, no solo por SOQL. La opción explain de la REST API sirve “para obtener información sobre cómo ejecuta Salesforce tu consulta, informe o vista de lista”, y devuelve los planes “ordenados del más óptimo al menos óptimo” (Get Feedback on Query Performance (se abre en una pestaña nueva), REST API Developer Guide, beta). La siguiente sección muestra cómo leer un plan.
Conocimiento para el examen. El optimizador de consultas se ejecuta para SOQL, informes y vistas de lista. Un filtro ineficiente, como distinto de o contiene, ralentiza un filtro de vista de lista o de informe tanto como ralentiza el código.
Informes con volumen
Sección titulada «Informes con volumen »Los informes son donde más trabaja el bibliotecario, porque un informe suele pedir muchos registros, de varios objetos, con muchos campos. Las buenas prácticas de Salesforce para los informes se leen como este capítulo en cuatro palabras (Reporting (se abre en una pestaña nueva), Best Practices for Deployments with Large Data Volumes, Winter ‘27):
- Menos registros que mirar (la consulta). “Usa un valor de los datos para segmentar la consulta. Por ejemplo, consulta un solo estado en lugar de todos los estados.” Y “Usa campos indexados en los filtros de los informes siempre que sea posible.”
- Menos uniones. Minimiza los objetos consultados en el informe y las relaciones usadas para construirlo.
- Una recuperación más ligera. “Reduce el número de campos consultados: añade a un informe, una vista de lista o una consulta SOQL solo los campos necesarios.”
- Resúmenes guardados, no recalculados. “Usa en el informe los datos resumidos guardados en el registro padre. Esta práctica es más eficiente que hacer que el informe resuma los registros hijos.”
Dos casos de estudio de la propia Salesforce lo muestran en acción. Los informes mensuales y anuales de un cliente sumaban sobre objetos personalizados de 4 millones y 9 millones de registros; la solución fue “un objeto personalizado de agregación que resumía los valores mensuales y anuales en el formato necesario para los informes requeridos”, rellenado mediante Apex por lotes (Data Aggregation (se abre en una pestaña nueva)). Otro tenía un informe sobre cuatro objetos, desde 314.000 cuentas hasta 2,3 millones de detalles de ventas, con muy poco filtrado. Las soluciones: más filtros, “tantos filtros como sea posible” indexables, menos datos en cada objeto, una Papelera de reciclaje vacía (“Los datos de la Papelera de reciclaje afectan al rendimiento de las consultas”) y ninguna regla de uso compartido compleja en esos objetos (Multi-Join Report Performance (se abre en una pestaña nueva)).
Mide la distribución y luego pregunta al optimizador
Sección titulada «Mide la distribución y luego pregunta al optimizador »Entonces, ¿cómo sabes lo que elegirá el bibliotecario? De dos maneras: cuenta los datos y luego pregunta al bibliotecario. Empieza por el recuento. Veinte millones de casos, filtro por estado. Alguien dice: “Status tiene seis valores, así que cada uno es más o menos un sexto”. ¿Por qué? Los datos reales no se reparten por igual porque una lista de selección tenga seis valores. Quizá sea un 70 % cerrados, un 15 % resueltos, un 8 % esperando al cliente, un 4 % escalados, un 2 % nuevos y un 1 % otros. La única respuesta útil es la distribución real, o una proyección defendible. Cuenta los registros agrupados por los valores del campo, como muestra la propia guía de Salesforce (Query Optimizer (se abre en una pestaña nueva)), y deja de discutir si el estado “parece selectivo”. Mide antes de optimizar. Un detalle: los recuentos de registros pueden incluir registros de la Papelera de reciclaje, así que decide de forma deliberada si cuentas los registros IsDeleted al medir (misma fuente). “Borramos 5 millones de registros, ¿por qué no es selectivo ahora?” ¿Se eliminaron de verdad, o están eliminados de forma lógica?
Contar te dice cosas de tus datos. No te dice lo que hará con ellos el bibliotecario. Para eso, ve un paso más allá con la herramienta Query Plan. En Winter ‘27 la encontrarás en la nueva Web Console, donde construyes una consulta en el SOQL Builder y ves su plan de consulta; la Developer Console, donde antes vivía la herramienta, ya no aparece por defecto en el menú Configuración (The Salesforce Developer’s Guide to the Winter ‘27 Release (se abre en una pestaña nueva); Web Console, generally available (se abre en una pestaña nueva)). Úsala para no decir “creo que Salesforce debería usar este índice”, sino preguntar al optimizador qué piensa hacer. Muestra la cardinalidad (cuántos registros espera encontrar el bibliotecario con la consulta), los campos, el tipo de operación inicial (leading operation type: un índice, el uso compartido, un recorrido de la tabla u otra operación; es decir, cómo empezará la consulta) y un coste. Gana el plan de menor coste, y un coste superior a 1 significa que el filtro no es selectivo (Query Plan Tool FAQ (se abre en una pestaña nueva)). En clase uso un conjunto de datos abierto de aeropuertos para mostrarlo: un pequeño cambio en un filtro mueve el coste estimado de algo como 0,69 a 0,09. Mucho mejor que discutir si una consulta “parece eficiente”. Y el coste no es tiempo de ejecución: 0,09 no significa 0,09 segundos. Es una medida relativa para comparar planes, no un cronómetro.
No adivines lo que hará el optimizador. Pregúntaselo.
Más de un índice: ¿cuál dirige?
Sección titulada «Más de un índice: ¿cuál dirige? »Ahora el bibliotecario tiene más de una opción. Las consultas reales rara vez tienen un solo filtro. Supón que pides a la biblioteca todos los libros sobre reparaciones del hogar y de A. Ortiz. Hay un cajón por tema y un cajón por autor. ¿Cuál abre el bibliotecario? El que más acota. Reparaciones del hogar podrían ser miles de libros; A. Ortiz podrían ser doce. Saca las doce fichas del autor y luego comprueba el tema en cada uno de esos libros. Con nuestras cuatro palabras: el índice del autor dirige la consulta, el tema se comprueba en los doce libros encontrados, y solo los libros que pasan ambos se recuperan. Eso es lo que Salesforce quiere decir con el índice que dirige la consulta: el optimizador “determina el mejor índice desde el que dirigir la consulta” (misma fuente), y los demás filtros se comprueban por el camino.
Con AND, los filtros se ayudan entre sí. El propio ejemplo de Salesforce: en un objeto donde el umbral es 150.000, StageName = 'Closed Won' coincide con 49.899 y CloseDate = THIS_WEEK con unos 3.000, así que los dos son selectivos. Pero incluso si Closed Won coincidiera con 250.000, por encima de la línea por sí solo, la combinación todavía puede ser selectiva: el optimizador considera selectivo un AND cuando cada filtro apunta a menos del doble de su umbral, o cuando los registros que coinciden con ambos están por debajo del umbral (Lightning Platform Query Optimizer (se abre en una pestaña nueva)). Steve Trucking: Retail_Partner__c = 'Redrock' AND Scheduled_Date__c = TODAY. El socio solo pueden ser millones; junto con la fecha de hoy, es un conjunto pequeño.
Con OR, es al revés. “Con el operador OR, cada filtro debe cumplir el umbral por separado” (misma fuente), y “Todos los campos de la cláusula OR deben estar indexados para que se use algún índice” (Indexes (se abre en una pestaña nueva), Winter ‘27). Un campo sin indexar en un OR, o un filtro por encima de su umbral, y el bibliotecario recorre las estanterías. Así que no ajusto SOQL cláusula a cláusula; miro la forma completa de la recuperación. Y cuando el problema es un OR, la propia solución de Salesforce es dividirlo: “Si usas dos campos indexados unidos por un OR en la cláusula WHERE, los resultados de tu búsqueda pueden superar el umbral del índice. Divide la consulta en dos consultas y une los resultados” (SOQL and SOSL (se abre en una pestaña nueva), buenas prácticas, Winter ‘27). Dos preguntas que el bibliotecario puede responder cada una desde un cajón, en lugar de una que tiene que responder recorriendo las estanterías.
AND: dirige desde el cajón más pequeño y comprueba el resto en esos libros. Rápido.
OR, con un cajón para cada parte: los dos cajones y luego los libros de las dos listas.
OR, con una parte que no tiene cajón: recorre todas las estanterías. Lento.
Índices de dos columnas
Sección titulada «Índices de dos columnas »Ahora una variante, y es donde vuelve a entrar la recuperación. ¿Y si dos campos casi siempre se preguntan juntos? Salesforce puede construir un solo índice sobre los dos: un índice personalizado de dos columnas. Son “útiles para las vistas de lista y las situaciones en las que quieres usar un campo para seleccionar los registros que se muestran y otro campo para ordenarlos. Por ejemplo, una vista de lista de Account que selecciona por State y ordena por City puede usar un índice de dos columnas con State en la primera columna y City en la segunda” (Indexes (se abre en una pestaña nueva), Winter ‘27). Y cuando dos campos son un filtro habitual juntos, “un índice de dos columnas sobre f1__c,f2__c es más eficiente que índices separados sobre f1__c y f2__c” (misma fuente).
Piensa en un catálogo de fichas ordenado por tema y, dentro de cada tema, por autor. Pide reparaciones del hogar de A. Ortiz y vas directo al sitio. En clase siempre añado: el orden de los campos importa. La primera columna es la que usas para seleccionar: sirve a la consulta, a encontrar. La segunda se mantiene ordenada dentro de la primera, como los autores dentro de cada tema: sirve a lo que pasa después de encontrar, devolver los registros en el orden que quieres. Por eso el ejemplo de Salesforce es una vista de lista: selecciona las cuentas de este estado y muéstralas ordenadas por ciudad. Pon los campos al revés y el índice ya no encaja con la pregunta. Un cajón ordenado por tema y luego por autor no ayuda mucho si solo conoces el autor. Para Steve Trucking, podría ser primero el socio minorista y luego la fecha programada. El valor no es que “dos columnas ganan a una”. Es que el índice encaja con un patrón importante y repetible.
Un detalle más de la misma página: los índices de dos columnas “pueden tener valores nulos en la segunda columna, mientras que los índices de una sola columna no pueden, salvo que el servicio de atención al cliente de Salesforce haya habilitado expresamente la opción de incluir nulos”.
Conocimiento para el examen. Un índice personalizado de dos columnas: la primera columna para seleccionar, la segunda para ordenar o acotar más; el orden importa; se permiten nulos en la segunda columna.
Antes de pedir un índice
Sección titulada «Antes de pedir un índice »Ya tienes todas las herramientas de indexación: índices estándar, índices personalizados, External ID, índices de dos columnas. Así que cuando alguien dice “este panel va lento, indexemos algo”, la pregunta no es “¿podemos convencer a alguien de que cree uno?”. Es ¿debería indexarse este campo? Recuerda del módulo 2: cada solicitud de índice personalizado es una conversación con el servicio de atención al cliente de Salesforce, y cada índice es otra copia que se escribe en cada guardado. Este es el argumento que quiero ver antes de pedirlo:
- Usado repetidamente. Una forma importante y cotidiana de encontrar registros, no un informe que alguien ejecuta una vez al año.
- Valores que de verdad acotan la población. El filtro tiene que quedar por debajo del umbral: el 10 % del primer millón de registros para un índice personalizado, con su tope.
- Una distribución conocida. Contada, no adivinada: cuántos registros por valor, hoy.
- Una necesidad operativa. Personas o procesos que dependen de él: una vista de lista, un informe, una integración, un agente.
- Un diseño que sobrevive al crecimiento. Todavía por debajo del umbral en el tercer año y en el quinto, con el 30 % anual del módulo anterior.
- Preguntado de la manera correcta. Igual a o empieza por, no contiene ni distinto de, o el índice no se usará por muy justificado que esté.
Un atajo que conviene evitar: marcar un campo como External ID solo para obtener el índice. Si no es realmente un identificador de otro sistema, no lo etiquetes así por un efecto secundario de rendimiento. Los metadatos deben decir la verdad. Ese es tu argumento para la solicitud, y es el mismo argumento que hace el bibliotecario cada vez que se ejecuta la consulta. No intento maximizar el número de índices. Intento crear las vías de recuperación correctas.
Skinny tables
Sección titulada «Skinny tables»Volvamos a las cuatro palabras una última vez. Incluso con un buen índice, la unión y la recuperación siguen costando algo en un objeto enorme: recuerda del módulo 1 que los campos estándar y personalizados viven en tablas separadas, unidas entre bastidores.
Este es el momento que describo en clase. Un objeto gigante, millones de registros, y tus informes, vistas de lista y consultas importantes vuelven una y otra vez al mismo pequeño conjunto de campos. Miras el patrón y lo sabes en el fondo: ojalá hubiera una versión más pequeña y plana de este objeto, construida solo en torno a estos campos.
Eso es una skinny table (una tabla reducida). Y antes que nada, aclaremos una cosa, porque la gente las confunde: una skinny table no es un índice. Es una herramienta distinta para un trabajo distinto. Un índice es una pequeña copia de un campo, mantenida en orden, para que el bibliotecario pueda encontrar registros: ayuda a la consulta. Una skinny table es una copia del propio registro, recortada a solo las columnas que sigues pidiendo, con los campos estándar y personalizados uno al lado del otro en una sola tabla: ayuda a traerlos de vuelta, la recuperación, sin la unión. En palabras de Salesforce, es “una tabla personalizada que contiene un subconjunto de campos de un objeto base de Salesforce, estándar o personalizado” (Optimize Large Data Set Queries & Searches (se abre en una pestaña nueva), Trailhead).
Es otra copia deliberada hecha para la recuperación, mantenida sincronizada con el objeto, y el mismo intercambio que cada copia de este capítulo: las copias hacen más rápidas las lecturas, y las copias hay que mantenerlas.
¿Qué te aporta? Salesforce enumera las ventajas:
- Sin unión. “Las operaciones de solo lectura que hacen referencia únicamente a campos de una skinny table no requieren una unión adicional y, en consecuencia, pueden rendir mejor” (Skinny Tables (se abre en una pestaña nueva), Best Practices for Deployments with Large Data Volumes, Winter ‘27).
- Una recuperación más ligera. “Al tener filas más estrechas y menos datos que recorrer que el objeto base de Salesforce, las skinny tables permiten recuperar más filas por lectura de la base de datos, lo que aumenta el rendimiento al leer de un objeto grande” (Trailhead, misma fuente).
- Menos filas. Una skinny table “omite los registros eliminados de forma lógica”, los que siguen en la Papelera de reciclaje (guía de LDV, misma fuente).
- Los índices vienen incluidos. “Los índices personalizados de la tabla base también se replican, y normalmente rinden mejor gracias a la reducción de uniones de tablas” (Trailhead). Así que el índice sigue dirigiendo la consulta; la skinny table acorta el resto del viaje.
En términos de biblioteca: imagina una carpeta en el mostrador con una línea por libro, solo con el puñado de datos que la gente pide una y otra vez. La mayoría de las preguntas se responden desde la carpeta, sin ir a las estanterías a abrir cada libro.
¿Y quién decide cuándo usarla? El bibliotecario. “La plataforma determina en tiempo de ejecución de la consulta cuándo tiene sentido usar skinny tables, así que no tienes que modificar tus informes ni desarrollar código Apex ni llamadas a la API” (Trailhead). Pero solo cuando encaja: la consulta, el informe o la vista de lista tiene que pedir campos que estén todos en la skinny table. Añade una columna que no esté, y el bibliotecario vuelve al objeto completo y a la unión.
Aquí importan los hechos:
- No puedes construir una tú mismo. “Si quieres usar skinny tables, ponte en contacto con el servicio de atención al cliente de Salesforce”, y “No puedes crear, acceder ni modificar skinny tables por tu cuenta.” Si el informe o la consulta cambian, por ejemplo para añadir un campo, el soporte tiene que actualizar la definición (guía de LDV).
- Funcionan en objetos personalizados y en Account, Contact, Opportunity, Lead y Case, y “pueden mejorar el rendimiento de informes, vistas de lista y SOQL” (misma fuente).
- Como máximo 200 columnas, y ningún campo de otros objetos (misma fuente). El material más antiguo dice 100: ese era el límite en ediciones anteriores de la misma guía (Winter ‘16).
- Los tipos de campo permitidos están enumerados: casilla de verificación, divisa, fecha, fecha y hora, correo electrónico, número, porcentaje, teléfono, lista de selección múltiple, texto, área de texto, área de texto larga y URL (misma fuente).
- Se copian a los sandboxes Full; los demás sandboxes necesitan que el soporte las active (misma fuente).
Y Salesforce lo dice claramente: “Las skinny tables no son una varita mágica para los problemas de rendimiento. Mantener tablas separadas que guardan copias de datos vivos tiene un coste adicional. Usarlas en un contexto inadecuado puede degradar el rendimiento en lugar de mejorarlo” (misma fuente). Es el mismo intercambio que cada copia de este capítulo: las copias hacen más rápidas las lecturas, y las copias hay que mantenerlas.
Así que piensa en ellas cuando un conjunto estable de campos sirve repetidamente lecturas importantes de gran volumen en un objeto enorme, no en “metamos ahí el objeto entero”. Y una skinny table no hace selectivo un mal filtro. Pide el 95 % de 50 millones de registros y sigues teniendo un gran problema de recuperación. Los índices y los filtros selectivos te dan el impulso para la consulta; la skinny table ayuda con la unión y la recuperación. Trabajan juntos, y no son lo mismo.
Conocimiento para el examen. Una skinny table no es un índice. La crea el servicio de atención al cliente de Salesforce; guarda hasta 200 columnas de un solo objeto (campos estándar y personalizados juntos, ningún campo de otros objetos), deja fuera los registros eliminados de forma lógica, evita la unión entre el almacenamiento de campos estándar y personalizados, y se usa automáticamente cuando una consulta, un informe o una vista de lista usa solo sus campos. Objetos personalizados más Account, Contact, Opportunity, Lead y Case. Solo se copia a los sandboxes Full.
Divisiones: dividir un objeto enorme
Sección titulada «Divisiones: dividir un objeto enorme »Una herramienta más de la misma familia, y entra en el examen: las divisiones. “Las divisiones son una forma de particionar los datos de las implementaciones grandes para reducir el número de registros que devuelven las consultas y los informes. Por ejemplo, una implementación con muchos registros de clientes podría crear divisiones llamadas US, EMEA y APAC para separar a los clientes en grupos más pequeños que probablemente tengan pocas interrelaciones” (Divisions (se abre en una pestaña nueva), Best Practices for Deployments with Large Data Volumes, Winter ‘27).
En términos de biblioteca, es dar a cada región su propia ala, para que la mayoría de las preguntas solo recorran un ala. Y tampoco es un índice: divide los registros en grupos, y Division es uno de los campos indexados estándar del módulo 2, así que el bibliotecario puede ir directo a los registros de una división. Como con las skinny tables, no lo activas tú. “Para usar divisiones, tu organización debe tener más de un millón de registros en un solo objeto y más de 35 licencias. Salesforce ofrece un soporte especial para particionar los datos por divisiones, que puedes habilitar contactando con el servicio de atención al cliente de Salesforce” (misma fuente). Las divisiones encajan con datos que de verdad se reparten en grupos con los que la gente trabaja por separado. No son una forma de sortear un filtro que no es selectivo.
Conocimiento para el examen. Las divisiones particionan los datos de una organización grande (por ejemplo, US, EMEA, APAC) para reducir los registros que devuelven las consultas y los informes. Necesitan más de un millón de registros en un objeto y más de 35 licencias, y las habilita el servicio de atención al cliente de Salesforce.
Las estadísticas de la base de datos: el cuaderno del bibliotecario
Sección titulada «Las estadísticas de la base de datos: el cuaderno del bibliotecario »Recuerda las preconsultas del principio de este módulo: antes de elegir un camino, el bibliotecario comprueba cuántos registros es probable que coincidan. ¿Cuenta todos los libros cada vez que alguien pregunta? No. Lleva un cuaderno: cuántos libros hay, cuántos de cada tema, cómo se reparten. Eso son las estadísticas de la base de datos. En palabras de Salesforce: “Las bases de datos modernas recopilan estadísticas sobre la cantidad y los tipos de datos que almacenan, y usan esa información para ejecutar las consultas de forma eficiente. Debido al enfoque multiinquilino de la arquitectura de software de Salesforce, la plataforma debe mantener su propio conjunto de información estadística para ayudar a la base de datos a entender la mejor forma de acceder a los datos” (Database Statistics (se abre en una pestaña nueva), Best Practices for Deployments with Large Data Volumes, Winter ‘27).
Y aquí está el truco: el cuaderno no se actualiza sobre la marcha. “Cuando se crean, actualizan o eliminan grandes cantidades de datos mediante la API, la base de datos debe recopilar estadísticas antes de que la aplicación pueda acceder a los datos de forma eficiente. Actualmente, este proceso de recopilación de estadísticas se ejecuta cada noche” (misma fuente).
Así que imagina esto. Anoche, el cuaderno dice 1 millón de contactos, 50.000 de ellos en Arizona: por debajo de la línea del índice personalizado de 100.000, así que State = 'AZ' parece selectivo. Esta tarde una migración carga otro millón de contactos, todos en Arizona. Ahora la tabla tiene 2 millones de contactos y 1.050.000 en Arizona, muy por encima de la nueva línea de 150.000. Pero el cuaderno sigue diciendo 50.000. Hasta la ejecución de estadísticas de esta noche, el bibliotecario planifica con los recuentos de ayer.
Hasta la ejecución de estadísticas de esta noche, el bibliotecario planifica con los recuentos de anoche.
Por eso digo en clase: carga un millón de registros y puede que veas cambiar el rendimiento, y puede tardar hasta el día siguiente en estabilizarse. La razón no es que el índice se rompa. Es que el cuaderno va un día por detrás. Así que:
- Planifica las grandes cargas y los grandes borrados para que las estadísticas nocturnas se ejecuten antes de que la gente dependa del rendimiento: antes de una noche tranquila, no una hora antes de la puesta en producción.
- Prueba el rendimiento al día siguiente de una gran carga, no una hora después. Si no, estás midiendo el cuaderno de ayer.
- Cuenta también con que los borrados influyen. Salesforce nombra las creaciones, las actualizaciones y los borrados. Archiva 5 millones de registros hoy y los recuentos se pondrán al día esta noche.
Conocimiento para el examen. Salesforce mantiene sus propias estadísticas de la base de datos, los recuentos que usa el optimizador de consultas para elegir un plan. Tras grandes cargas, actualizaciones o borrados de datos mediante la API, hay que recopilar estadísticas antes de que las consultas se ejecuten de forma eficiente; la recopilación se ejecuta cada noche.
Cuando va lento: indexar, reescribir, rediseñar o archivar
Sección titulada «Cuando va lento: indexar, reescribir, rediseñar o archivar »Ya sabes cómo piensa el bibliotecario. Así que tarde o temprano alguien acude al arquitecto: “Esta consulta va lenta. ¿Podemos ponerle un índice?”. Quizá. Pero esa no es mi primera respuesta. Mi primera pregunta es ¿por qué va lenta? Un índice es una herramienta. A veces habría que reescribir la consulta, a veces el modelo está luchando contra nosotros, a veces mantenemos activos 50 millones de registros que no deberían estarlo, y a veces estamos a punto de arreglar un caso aislado añadiendo complejidad permanente. No receto el remedio hasta entender la enfermedad.
Y mide antes de cambiar nada. ¿Cuántos registros, y a qué ritmo crecen? ¿Cómo se distribuyen los valores del filtro? ¿Qué está ya indexado? ¿Qué dice Query Plan? ¿Cuántas filas devuelve la consulta, y el problema es siquiera la recuperación, o es el uso compartido, los bloqueos o la automatización? ¿Qué pasa en el tercer año y en el quinto? “La consulta devuelve 400.000 registros, así que necesitamos un índice” no me dice lo suficiente. ¿400.000 de cuántos? De 500.000, es una selectividad pésima; de 50 millones, es otra conversación. Haz primero las cuentas.
Un índice es una respuesta, no la respuesta.
Esta es la decisión que quiero que practiquen los arquitectos:
Indexa cuando un patrón importante y repetible tiene un campo adecuado con una distribución útil, y el índice es una solución limpia y general: la lista de Antes de pedir un índice. El ejemplo de Steve Trucking: la referencia de entrega de cada socio minorista, un External ID único en la orden de trabajo. Los agentes de atención encuentran con ella una entrega entre 9 millones, cientos de veces al día.
Reescribe cuando el modelo es razonable pero la pregunta impide al bibliotecario usar un buen camino. Antes de cambiar el esquema: ¿podemos usar un filtro positivo más selectivo, acotar por tiempo, evitar un comodín inicial, sustituir una condición negativa amplia por una positiva pequeña, dividir la recuperación, o reconocer que en realidad es un problema de búsqueda de texto que corresponde a SOSL y no a un montón de OR en SOQL (el próximo módulo)? No cambies la arquitectura para compensar una mala pregunta cuando puedes hacer una mejor. Y para “todo lo que ha cambiado desde la última ejecución”, filtra por SystemModstamp, que está indexado, en lugar de LastModifiedDate, que no lo está (las tablas del módulo 2); el capítulo de integración trata los envíos incrementales. Dos de los casos de estudio de Salesforce también son reescrituras. En uno, una consulta de los registros creados en los últimos tres días coincidía con demasiados registros para el umbral estándar y se ejecutaba despacio. Reescrita con ORDER BY CreatedDate LIMIT 99999, “no se hicieron las comprobaciones del umbral, y se usó el índice de CreatedDate para encontrar los registros” (Sort Optimization on a Query (se abre en una pestaña nueva)). Es un caso documentado, no un truco general: compruébalo con el Query Plan para tu propia consulta. En el otro, una integración usaba un usuario dentro de la jerarquía de uso compartido para limitar lo que leía, sobre varios millones de registros, y sus consultas tardaban minutos. El uso compartido “funciona muy bien para las interacciones de la interfaz de usuario”, pero “cuando se usa como filtro de datos de gran volumen en una consulta SOQL, el rendimiento puede resentirse”; la solución fue “dar a la consulta acceso a todos los datos y luego usar filtros selectivos”, o extraer solo lo que cambió (API Performance (se abre en una pestaña nueva)). Un usuario de integración que puede leerlo todo es una decisión de seguridad además de rendimiento, así que tómala de forma deliberada.
Rediseña cuando la recuperación importa y el propio modelo la encarece. Las partidas de orden de trabajo, unos 14,5 millones en cinco años, y una consulta importante necesita las partidas recientes de un socio minorista. Pero el socio vive en la orden de trabajo, no en la partida. Copia Retail_Partner__c en la partida, rellénalo cuando se crea la partida, quizá indéxalo, y la consulta puede filtrar directamente el hijo. Eso es desnormalización deliberada: datos duplicados y lógica para mantenerlos correctos, a cambio de un camino directo a través de millones de registros (Diseña hasta la tercera forma normal y luego retrocede expone el caso completo). El rediseño también puede ser pequeño. Si “sin asignar” es un estado de negocio real, guárdalo: una consulta puede pedir Routing_Status__c = 'Unassigned' y usar un índice, mientras que Route__c = null no puede por defecto. Y si los valores vacíos ya están ahí, el propio caso de estudio de Salesforce muestra una salida: un campo de fórmula que convierte un valor vacío en una palabra, IF(ISBLANK(Status__c), "blank", Status__c). Es determinista, así que se puede indexar (módulo 2), y la consulta pasa a ser Status_Value__c = 'blank' (Indexing with Nulls (se abre en una pestaña nueva)).
Archiva cuando el historial que ya no pertenece a la carga de trabajo activa domina la población que consultas. Cincuenta millones de registros, y el proceso operativo solo necesita los últimos 18 meses. Puedes pasar mucho tiempo haciendo más rápidas las consultas sobre los 50 millones, o puedes preguntar ¿por qué siguen activos los 50 millones? A veces la mejor optimización de consultas es una población activa más pequeña (Si no archivas hoy…).
Cuatro respuestas a una consulta lenta. Haz primero las cuentas y luego elige.
Y una advertencia. Alguien aprende que Salesforce tiene índices estándar, índices personalizados, External ID, índices de dos columnas y skinny tables, y empieza a buscar sitios donde usarlos todos. Eso es al revés. Empieza por qué intentamos recuperar, con qué volumen, con qué frecuencia, con qué distribución y cómo cambiará eso, y luego elige el mecanismo más pequeño que lo resuelva de forma limpia.
Correcto no es lo mismo que escalable
Sección titulada «Correcto no es lo mismo que escalable »Una consulta SOQL puede ser sintácticamente perfecta, devolver exactamente los registros correctos, ejecutarse de maravilla en una organización de desarrollo y aun así ser errónea desde el punto de vista de la arquitectura. La guía Well-Architected de Salesforce lo incluye como antipatrón: “Pruebas a pequeña escala con volúmenes de datos mínimos (el comportamiento del optimizador de consultas cambia drásticamente a partir de 10 millones de registros, lo que hace engañosos los resultados a pequeña escala)” (Availability & Performance Patterns (se abre en una pestaña nueva)). En un sandbox con 5.000 entregas, un recorrido de la tabla es minúsculo y la consulta parece instantánea. En producción con 50 millones, el mismo SOQL, el mismo Apex, la misma lógica es un problema muy distinto. No cambió nada del código. Cambió el Número de Ceros. Por eso la arquitectura de recuperación no puede esperar a las pruebas de rendimiento del final: el modelo de datos ya decidió qué caminos estarían disponibles.
Así que demuestra el diseño con un volumen realista, no con 500 registros, no con “parecía rápido en mi sandbox de desarrollo”. E igual de importante, una distribución realista. Diez millones de registros de datos de prueba perfectamente aleatorios pueden decirte poco sobre un sistema de producción donde el 80 % comparte un mismo estado, el 40 % pertenece a un mismo socio minorista, la mayor parte del historial está completada y una pequeña ventana activa recibe casi todas las actualizaciones. La selectividad depende de la distribución; las pruebas de rendimiento tienen que modelar la forma de los datos, no solo el recuento. La guía Well-Architected de Salesforce dice lo mismo: “Los sandboxes de desarrollo solo copian la configuración y no contienen datos. Probar con volúmenes realistas en un sandbox de copia completa saca a la luz los problemas de escalabilidad antes de que lo hagan los clientes” (Resource and Cost Optimization (se abre en una pestaña nueva)). Para un trabajo serio de gran volumen, importa un sandbox Full: puede llevar el volumen y la distribución de producción, y las skinny tables de producción se copian allí. Prueba pronto el comportamiento básico, pero antes de salir a producción quiero pruebas de que el diseño sobrevive al Número de Ceros que esperas.
Un desarrollador acaba escribiendo SELECT … FROM … WHERE …, pero el éxito de esa consulta se decidió meses antes: por el modelo de datos, los tipos de campo, qué valores podían ser nulos, qué relaciones existían, qué campos estaban indexados, cómo se distribuían los valores, cuánto historial seguía activo y cuántos datos esperábamos dentro de cinco años. La consulta no arregla esas decisiones. Las hereda.
Sin interfaz, agentes e IA: el bibliotecario sigue decidiendo
Sección titulada «Sin interfaz, agentes e IA: el bibliotecario sigue decidiendo »Ahora una pregunta que me hacen cada vez más. ¿Qué pasa cuando nadie abre una vista de lista? En abril de 2026 Salesforce lo dijo claramente: “Todo en Salesforce es ahora una API, una herramienta MCP o un comando de CLI, y los agentes pueden usarlo todo” (Introducing Salesforce Headless 360 (se abre en una pestaña nueva), 15 de abril de 2026). Sin navegador, sin pantalla, un agente de IA que pide registros directamente. ¿Se jubila el bibliotecario?
No. Si los datos viven en el núcleo de Salesforce, cada una de esas solicitudes sigue convirtiéndose en una consulta, y la ejecuta el mismo bibliotecario con las mismas tres comprobaciones. Mira la herramienta que Salesforce da a los agentes de IA para leer registros a través de su servidor MCP alojado. Se llama soqlQuery, “Ejecuta una consulta SOQL para recuperar registros de Salesforce”, y viene con esta instrucción para el agente: “Incluye siempre una cláusula WHERE para filtrar los resultados y una cláusula LIMIT para controlar el tamaño del resultado. Para objetos grandes, filtra por campos indexados (Id, Name, claves externas, External ID) para evitar errores de tiempo de espera” (SObject All (se abre en una pestaña nueva), Hosted MCP Servers, consultado el 2026-10-22). Salesforce está enseñando a los agentes las comprobaciones del nitro.
Así que trabajar sin interfaz no hace menos importante este módulo. Lo hace más importante. Una persona abre una vista de lista lenta unas cuantas veces al día y se queja. Un agente puede hacer la misma pregunta cientos de veces por hora, y no sabe que Status tiene 9 millones de registros Completed, que el campo por el que filtra no tiene índice o que su “contiene” no puede usar uno. Solo conoce tus datos a través de los caminos que diseñaste. Cuanto más de tu negocio pasa por API y agentes, más deciden las elecciones del arquitecto si esas consultas obtienen el impulso: qué campos están indexados, qué identificadores son External ID, qué filtros siguen siendo selectivos a medida que crecen los datos. Y puedes comprobar las consultas de un agente igual que las de cualquier otro: pásalas por el Query Plan o por el explain de la REST API.
Un límite, para ser justos. Este es el bibliotecario de los datos del núcleo de Salesforce. La búsqueda de texto (FIND) tiene su propio motor, como trata el módulo 5, y los datos que viven en Data 360 se almacenan y procesan fuera del núcleo, con su propia forma de responder (módulo 6). Pero el principio se mantiene: sea cual sea el motor, alguien tiene que elegir un camino hacia tus datos, y un buen camino se diseña, no se espera.
Lo que decide aquí un arquitecto
Sección titulada «Lo que decide aquí un arquitecto »- Qué consultas, informes y vistas de lista importantes tienen un filtro selectivo desde el que pueda dirigir el optimizador.
- Si el Query Plan confirma el camino que esperas, con un volumen realista, antes de aceptar una consulta o un índice.
- Cómo se combinan los filtros AND y OR, y qué índice debería dirigir.
- Si un par de campos que se preguntan juntos justifica un índice de dos columnas, y en qué orden.
- Si un conjunto estable de campos en un objeto enorme justifica una skinny table, y lo que cuesta mantenerla.
- Cuando una consulta va lenta: si indexar, reescribir, rediseñar o archivar, después de hacer las cuentas.
- Cómo modelan las pruebas de rendimiento el volumen y la distribución reales, no solo el recuento de registros.
Explora
Sección titulada «Explora »- Salesforce Developers, Best Practices for Deployments with Large Data Volumes (Winter ‘27): Indexes (se abre en una pestaña nueva) and Skinny Tables (se abre en una pestaña nueva), checked 2026-11-01. ⟲
- Salesforce Architects, Well-Architected, Resource and Cost Optimization (se abre en una pestaña nueva), checked 2026-11-01: testing at realistic volume in a Full Copy sandbox; Query Selectivity. ⟲
- Salesforce Developers, Metadata API Developer Guide, CustomIndex (se abre en una pestaña nueva), checked 2026-11-01. ⟲
- Salesforce Developers, Lightning Platform Query Optimizer (se abre en una pestaña nueva) (Best Practices for Deployments with Large Data Volumes, Winter ‘27), checked 2026-11-01: what the optimizer does, and how AND and OR filters are judged. ⟲
- Salesforce Developers Blog, Announcing General Availability: Web Console (se abre en una pestaña nueva) (September 2026) and The Salesforce Developer’s Guide to the Winter ‘27 Release (se abre en una pestaña nueva) (October 2026), checked 2026-11-01: the query plan in Web Console; Developer Console hidden from Setup by default. ⟲
- Salesforce Architects, Platform Multitenant Architecture (se abre en una pestaña nueva), checked 2026-11-01: pre-queries and statistics by who’s asking (Queries). ⟲
- Salesforce Help, Developer Console Query Plan Tool FAQ (se abre en una pestaña nueva), version 5, checked 2026-11-01: reading a query plan, and cost above 1 means not selective. ⟲
- Salesforce Developers, Best Practices for Deployments with Large Data Volumes (Winter ‘27), Database Statistics (se abre en una pestaña nueva), checked 2026-11-01: statistics gathered nightly. ⟲
- Salesforce Architects, Well-Architected, Availability & Performance Patterns (se abre en una pestaña nueva), checked 2026-11-01: test at production-scale volume. ⟲
- Salesforce Developers, REST API Developer Guide, Get Feedback on Query Performance (se abre en una pestaña nueva) (beta), checked 2026-11-01: explain for a query, report or list view. ⟲
- Salesforce News, Introducing Salesforce Headless 360. No Browser Required. (se abre en una pestaña nueva), April 15, 2026, checked 2026-11-01. ⟲
- Salesforce Developers, Hosted MCP Servers, SObject All (se abre en una pestaña nueva), checked 2026-11-01: the soqlQuery tool and its instructions to agents. ⟲
- Trailhead, Optimize Large Data Set Queries & Searches (se abre en una pestaña nueva), checked 2026-11-01: skinny tables, fetching more rows per read, and replicated custom indexes. ⟲
- Salesforce Developers, Best Practices for Deployments with Large Data Volumes (Winter ‘27), checked 2026-11-01: Divisions (se abre en una pestaña nueva); best practices for Reporting (se abre en una pestaña nueva) and SOQL and SOSL (se abre en una pestaña nueva); case studies Data Aggregation (se abre en una pestaña nueva), Multi-Join Report Performance (se abre en una pestaña nueva), Indexing with Nulls (se abre en una pestaña nueva), Sort Optimization on a Query (se abre en una pestaña nueva) and API Performance (se abre en una pestaña nueva). ⟲
