2012-07-16 77 views
10

Esta es una pregunta de "mejores prácticas". Estamos teniendo discusiones internas sobre este tema y queremos obtener opiniones de un público más amplio.Usar SQL para devolver una cadena JSON

Necesito almacenar mis datos en una tabla tradicional MS SQL Server con columnas y filas normales. A veces necesito devolver un DataTable a mi aplicación web, y otras veces debo devolver una cadena JSON.

Actualmente, devuelvo la tabla a la capa intermedia y la analizo en una cadena JSON. Esto parece funcionar bien en su mayor parte, pero ocasionalmente toma un tiempo en grandes conjuntos de datos (analizar los datos, no devolver la tabla).

Estoy considerando revisar los procedimientos almacenados para devolver selectivamente una cadena DataTable o JSON. Simplemente agregaría un parámetro @isJson bit al SP.

Si el usuario desea la cadena en lugar de la tabla del SP podría ejecutar una consulta como esta:

DECLARE @result varchar(MAX) 
SELECT @result = COALESCE(@results ',', '') + '{id:"' + colId + '",name:"' + colName + '"}' 
    FROM MyTable 
SELECT @result 

Esto produce algo como lo siguiente:

{id:"1342",name:"row1"},{id:"3424",name:"row2"} 

Por supuesto, el usuario puede también obtiene la tabla pasando false al parámetro @isJson.

Quiero aclarar que el almacenamiento de datos no se ve afectado, ni tampoco ninguna de las vistas existentes y otros procesos. Esto es un cambio SOLAMENTE en los resultados de algunos procedimientos almacenados.

Mis preguntas son:

  1. Alguien ha probado esto en una aplicación de gran tamaño? Si es así, ¿cuál fue el resultado?
  2. ¿Qué problemas ha visto/esperaría con este enfoque?
  3. ¿Existe una forma mejor y más rápida para pasar de la tabla a JSON en SQL Server que no sea modificar el procedimiento almacenado de esta manera o analizar la cadena en el nivel medio?
+0

Cuéntanos más acerca de la capa intermedia. ¿Qué está tomando tanto tiempo? ¿Es código compilado? Debería ser muy posible escribir una aplicación que convierta un juego de registros en JSON y tenga un rendimiento bastante adecuado. – ErikE

+2

Suponiendo que escapa de sus caracteres especiales correctamente, esto es factible ... pero ... ¿por qué lo haría? SQL Server es un terrible motor de análisis de cadenas, y usted tiene un motor XML integrado que siempre puede escupir XML compatible de una manera relativamente eficiente. –

+1

@ErikE La mayoría de las tablas se convierten a json muy rápidamente. Esto solo surgió porque estamos analizando una tabla para FullCalendar. El análisis medio simplemente toma la tabla y usa un foreach para recorrer los campos y las filas para construir la cadena. Probablemente podamos arreglar algunas cosas en el medio para que funcione más rápido, pero si podemos evitar un paso adicional en el proceso haciendo que SQL lo haga ... ¿por qué no? – davids

Respuesta

8

Yo personalmente creo que el mejor lugar para este tipo de manipulación de cadenas está en el código del programa en un lenguaje completamente expresivo que tiene funciones y se puede compilar. Hacer esto en T-SQL no es bueno. El código de programa puede tener funciones rápidas que escapen correctamente.

Vamos a pensar un poco las cosas:

  • Al implementar nuevas versiones de las partes y piezas de su aplicación, ¿dónde está el mejor lugar para que esta funcionalidad esté?

  • Si tiene que restaurar su base de datos (y todos sus procedimientos almacenados) ¿afectará negativamente a algo? Si está implementando una nueva versión de su interfaz web, ¿la conversión JSON que está ligada a la base de datos causará problemas?

  • ¿Cómo va a escapar los caracteres correctamente? ¿Estás enviando alguna fecha? ¿En qué formato estarán las cadenas de fechas y cómo se convertirán en objetos de fecha reales en el otro extremo (si es necesario)?

  • ¿Cómo lo probará usted (y con pruebas automatizadas) para comprobar que funciona correctamente? ¿Cómo lo probará la regresión?

  • Las UDF de SQL Server pueden ser muy lentas. ¿Estás contento de utilizar una función lenta, o para acelerar tu código SQL cosas como Replace(Replace(Replace(Replace(Value, '\', '\\'), '"', '\"'), '''', '\'''), Char(13), '\n')? ¿Qué pasa con Unicode, \u y \x escapando? ¿Qué tal dividir '</script>' en '<' + '/script>'? (Tal vez eso no se aplique, pero tal vez lo haga, dependiendo de cómo use su JSON.) ¿Su procedimiento T-SQL va a hacer todo esto, y será reutilizable para diferentes conjuntos de registros, o lo reescribirá cada vez en cada SP que necesitas devolver JSON?

  • Es posible que solo tenga un SP que necesite devolver JSON. Por ahora. Algún día, es posible que tengas más. Entonces, si encuentras un error, debes arreglarlo en dos lugares. O cinco. O más.

Puede parecer que usted está haciendo las cosas más complicadas por tener la capa media hacer la traducción, pero te prometo que va a ser mejor en el largo plazo. ¿Qué sucede si su producto se amplía y comienza a ir paralelamente masivo? ¡Siempre puede lanzar más servidores web a bajo costo, pero no puede arreglar fácilmente la saturación de recursos del servidor de base de datos! Por lo tanto, no hagas que el DB haga más trabajo de lo que debería. Es una capa de acceso a datos, no una capa de presentación. Haz que haga la mínima cantidad de trabajo posible. Escribir código para todo lo demás. usted será feliz de haberlo hecho.

Consejos de velocidad para manejo de cadenas en una aplicación Web

  1. Asegúrese de que el código de la concatenación de cadenas Web no sufre de Schlemiel the Painter's Algorithm. Escriba directamente en el búfer de salida cuando se genera JSON (Response.Write), o utilice un objeto StringBuilder adecuado, o escriba las partes del JSON en un array y Join() más tarde. No haga una concatenación simple de vainilla a una cadena cada vez más larga una y otra vez.
  2. Desreferencia se opone lo menos posible. No conozco su lenguaje del lado del servidor, pero si resulta ser ASP Classic, no use nombres de campo; obtenga una referencia a cada campo en una variable o, como mínimo, utilice índices de campo entero. Desreferenciar un campo basado en su nombre dentro de un bucle es (mucho) peor rendimiento.
  3. Usar bibliotecas preconstruidas. No mueva el suyo cuando pueda usar una biblioteca probada y verdadera. El rendimiento debe ser igual o mejor que el suyo y (lo más importante) será probado y correcto.
  4. Si va a pasar el tiempo haciendo esto, hágalo lo suficientemente abstracto como para manejar la conversión de cualquier conjunto de registros, no solo el que tiene ahora.
  5. Utilice el código compilado. Siempre puede obtener el código más rápido cuando se compila, no se interpreta. Si identifica que las rutinas de conversión de JSON son verdaderamente el cuello de botella (y DEBE probar esto de verdad, no lo adivine), luego inserte el código en algo que esté compilado.
  6. Reduce las longitudes de cadena. Esto no es muy grande, pero si es posible use nombres json de una letra en lugar de muchas letras. Para un conjunto de registros gigante, se se suman a los ahorros en ambos extremos.
  7. Asegúrese de que esté GZipped. Esto no es tanto una mejora del lado del servidor, pero no podría mencionar el rendimiento de JSON sin estar completo.

fechas que pasan en JSON

Lo que recomiendo es utilizar un esquema JSON separado (sí en JSON, la definición de la estructura del conjunto de registros virtuales a seguir). Este esquema se puede enviar como un encabezado al "conjunto de registros" a seguir, o puede estar ya cargado en la página (incluido en los archivos base de JavaScript) por lo que no tiene que enviarse cada vez. Luego, en su devolución de llamada de JSON parse (o post-devolución de llamada en el objeto resultante final) busque en el esquema de la columna actual y realice las conversiones según sea necesario. Puede considerar usar formato ISO ya que en ECMAScript 5 strict mode se supone que es mejor soporte de fecha y su código puede simplificarse sin tener que cambiar el formato de datos (y una simple detección de objetos puede permitirle usar este código para cualquier navegador que lo soporte):

Fecha

Las fechas son ahora capaces tanto de análisis sintáctico y la salida de fechas con formato ISO.

El constructor Fecha ahora intenta analizar la fecha como si tuviera formato ISO, primero, luego pasa a las otras entradas que acepta.

Además, los objetos de fecha ahora tienen un nuevo método .toISOString() que imprime la fecha en un formato ISO. var date = new Date ("2009-05-21T16: 06: 05.000Z");

print (date.toISOString()); // 2009-05-21T16: 06: 05.000Z

+1

+1 Mejor que el mío. Eliminaré mi respuesta. –

+1

Usted plantea algunos puntos muy buenos y presenta un argumento convincente. Puede que no sea la solución correcta para la mayoría de las situaciones. Estábamos planificando un formato estándar para cosas como fechas y otras soluciones para problemas mencionados anteriormente, pero eran solo eso ... da la vuelta. MS solo necesita agregar un formato JSON como si ofrecieran un formato XML. – davids

+0

@davids ¿Me puede ayudar mi información adicional sobre cómo pasar las fechas en JSON? – ErikE

3

que no lo haría de esa manera se está haciendo (contatenating)

Usted puede intentar crear una función de SQL CLR que utiliza JSON.net y devuelve un varchar.

vemos aquí cómo crear funciones CLR de SQL: http://msdn.microsoft.com/en-us/library/w2kae45k(v=vs.80).aspx

Algo como esto (código no probado)

[Microsoft.SqlServer.Server.SqlFunction] 
public static SqlString MyFunctionName(int id) { 
    // Put your code here (maybe find the object you want to serialize using the id passed?) 
    using (var cn = new SqlConnection("context connection=true")) { 
     //get your data into an object 
     var myObject = new {Name = "My Name"}; 
     return new SqlString(Newtonsoft.Json.JsonConvert.SerializeObject(myObject)); 
    } 
} 
+0

¿En qué se diferencia el uso de json.net en una función CLR SQL de hacerlo en la capa intermedia? Nunca he usado una función CLR SQL, por lo que esta puede ser una pregunta tonta, pero ¿el resultado no será el mismo? – davids

+0

Podrá hacer algo como SELECCIONAR MyDb.dbo.ConvertToJson (id) desde Objetos para que tenga una llamada directa al DB. – turtlepick

+0

Recuerde que JSON puede ser realmente complicado, especialmente con campos de fecha y hora (es posible que también desee contabilizar caracteres especiales y todo eso ...) – turtlepick

Cuestiones relacionadas