Cuidado con la CompanyInfo

En muchas implantaciones, por no decir en todas, me encuentro un tipo concreto de personalizaciones que siempre siguen el mismo patrón.

Se trata de los típicos Textos legales, del registro mercantil, cláusulas varias, avisos periódicos, etc …

Normalmente, el requerimiento suele ser que necesitan imprimir una serie de textos semi-fijos (cambian con poca frecuencia) en las facturas u otros impresos, y la mayoría de implantadores optan por añadir dichos campos (que suelen depender de la empresa que lo imprima) en la tabla CompanyInfo.

No negaré que, en primera instancia, parece lógico ubicar estos campos en una tabla que está destinada a almacenar información relativa a la empresa, pero … a partir de AX 2012, se ha producido un cambio en el modelo de datos que, como veremos a continuación, puede ocasionarnos algún dolor de cabeza.

Dynamics AX 2012: Cambio en el modelo de datos

¿Habéis
intentado alguna vez abrir la tabla CompanyInfo directamente en la base de
datos SQL Server?

CompanyInfo SQL table

Efectivamente, no existe!!!

Se trata de un efecto colateral del uso de la herencia de tablas.

Me explico:

La tabla CompanyInfo hereda de la tabla OMInternalOrganization, que a su vez hereda de la tabla DirOrganizationBase, que esta hereda de DirPartyTable (ver imagen a continuación)

Herencia CompanyInfo

El resultado de esta jerarquía en SQL significa que todos los campos de CompanyInfo, OMInternalOrganization, DirOrganizationBase y DirPartyTable se encuentran todos en la tabla base (DirPartyTable).

En otras palabras, si ejecutamos una consulta tipo:

Select * from DirPartyTable

El sistema nos devolverá como resultado todos los datos existentes pertenecientes a estas cuatro tablas (en realidad nos devolverá incluso más datos porque existen otras “ramas” en esta jerarquía de herencia con algunas otras tablas).

 

El problema

Y bien, ¿qué problema puede ocasionarnos el hecho de añadir un par de campos en la tabla CompanyInfo donde almacenar textos legales?

Normalmente, cuando hablamos de textos legales, suelen ser párrafos de 3 o 4 líneas de longitud que acaban siendo campos de tipo “Memo” o, por ejemplo “String” de 1000 caracteres de longitud.

Y ¿Qué otras tablas tienen relación con la tabla dirPartyTable?

Clientes y proveedores (entre otras).

Veamos un ejemplo. Veamos que sucede cuando se ejecuta el formulario de clientes.

Si echamos un vistazo a los datasources existentes dentro del formulario de clientes:

img0003

 

Vemos que aparece, tanto la tabla base como diversas de las tablas hijas,  varias veces y relacionadas directa o indirectamente con la tabla CustTable.

Veamos cómo se comporta el sistema cuando abrimos el formulario.

Primero activamos el seguimiento de instrucciones SQL en las opciones de usuario:

 

img0004

 

Ahora abrimos el formulario CustTable.

Podemos hacerlo directamente desde el AOT o bien dando doble clic a alguno de los registros que nos aparezcan en el ListPage de clientes (el resultado de la query es ligeramente distinto en un caso u en otro).

En nuestro caso, abrimos el formulario de clientes y tenemos que la consulta que se ejecuta sobre SQL es:

SELECT T1.ACCOUNTNUM,T1.DEL_NAME,T1.DEL_ADDRESS,T1.DEL_PHONE,T1.DEL_TELEFAX,T1.INVOICEACCOUNT,T1.CUSTGROUP,T1.LINEDISC,
T1.PAYMTERMID,T1.CASHDISC,T1.CURRENCY,T1.INTERCOMPANYAUTOCREATEORDERS,T1.SALESGROUP,T1.BLOCKED,T1.ONETIMECUSTOMER,T1.ACCOUNTSTATEMENT,T1.CREDITMAX,T1.MANDATORYCREDITLIMIT,T1.DEL_DIMENSION,T1.DEL_DIMENSION2_,
T1.DEL_DIMENSION3_,T1.DEL_DIMENSION4_,T1.DEL_DIMENSION5_,T1.VENDACCOUNT,T1.DEL_TELEX,T1.PRICEGROUP,T1.MULTILINEDISC,T1.ENDDISC,T1.VATNUM,T1.DEL_COUNTRYREGIONID,T1.INVENTLOCATION,T1.DLVTERM,T1.DLVMODE,T1.MARKUPGROUP,T1.CLEARINGPERIOD,T1.DEL_ZIPCODE,
T1.DEL_STATE,T1.DEL_COUNTY,T1.DEL_URL,T1.DEL_EMAIL,T1.DEL_CELLULARPHONE,T1.DEL_PHONELOCAL,T1.FREIGHTZONE,T1.CREDITRATING,T1.TAXGROUP,T1.STATISTICSGROUP,T1.PAYMMODE,T1.COMMISSIONGROUP,T1.BANKACCOUNT,T1.PAYMSCHED,T1.DEL_NAMEALIAS,T1.CONTACTPERSONID,T1.INVOICEADDRESS,T1.OURACCOUNTNUM,
T1.SALESPOOLID,T1.INCLTAX,T1.CUSTITEMGROUPID,T1.NUMBERSEQUENCEGROUP,T1.DEL_LANGUAGEID,T1.PAYMDAYID,T1.LINEOFBUSINESSID,T1.DESTINATIONCODEID,T1.SUPPITEMGROUPID,T1.TAXLICENSENUM,T1.WEBSALESORDERDISPLAY,T1.PAYMSPEC,T1.BANKCENTRALBANKPURPOSETEXT,T1.BANKCENTRALBANKPURPOSECODE,
T1.DEL_PRINTMODULETYPE,T1.DEL_CITY,T1.DEL_STREET,T1.DEL_PAGER,T1.DEL_SMS,T1.INTERCOMPANYALLOWINDIRECTCREATION,T1.PACKMATERIALFEELICENSENUM,T1.DLVREASON,T1.FORECASTDMPINCLUDE,T1.SALESCALENDARID,T1.CUSTCLASSIFICATIONID,T1.INTERCOMPANYDIRECTDELIVERY,T1.SHIPCARRIERACCOUNT,
T1.INVENTSITEID,T1.ORDERENTRYDEADLINEGROUPID,T1.SHIPCARRIERID,T1.SHIPCARRIERFUELSURCHARGE,T1.SHIPCARRIERBLINDSHIPMENT,T1.DEL_PARTYTYPE,T1.DEL_PARTYID,T1.SHIPCARRIERACCOUNTCODE,T1.DEL_PROJPRICEGROUP,T1.SYNCENTITYID,T1.SYNCVERSION,T1.SALESDISTRICTID,T1.SEGMENTID,T1.SUBSEGMENTID,
T1.RFIDITEMTAGGING,T1.RFIDCASETAGGING,T1.RFIDPALLETTAGGING,T1.COMPANYCHAINID,T1.DEL_MAINCONTACTID,T1.PARTY,T1.IDENTIFICATIONNUMBER,T1.PARTYCOUNTRY,T1.PARTYSTATE,T1.DEFAULTDIMENSION,T1.CUSTEXCLUDECOLLECTIONFEE,T1.CUSTEXCLUDEINTERESTCHARGES,T1.MAINCONTACTWORKER,
T1.CREDITCARDADDRESSVERIFICATION,T1.CREDITCARDCVC,T1.CREDITCARDADDRESSVERIFICATIONVOID,T1.CREDITCARDADDRESSVERIFICATIONLEVEL,T1.PBACUSTGROUPID,T1.DEL_COREGNUM_CZ,T1.DEL_PSACOMPANY,T1.DEL_PSACONTRACTNOTUSED,T1.DEL_PSADESIGNID,T1.DEL_SUBMITED,T1.USEPURCHREQUEST,T1.MCRMERGEDPARENT,
T1.MCRMERGEDROOT,T1.CASHDISCBASEDAYS,T1.DAXINTEGRATIONID,T1.DEFAULTDIRECTDEBITMANDATE,T1.DEFAULTINVENTSTATUSID,T1.ENTRYCERTIFICATEREQUIRED_W,T1.EXPRESSBILLOFLADING,T1.ISSUEOWNENTRYCERTIFICATE_W,T1.PDSCUSTREBATEGROUPID,T1.PDSFREIGHTACCRUED,T1.PDSREBATETMAGROUP,T1.USECASHDISC,
T1.DEL_CUSTVENDREGNUM_EE,T1.DEL_PDSREGIONCODE,T1.DEL_PDSSELLABLEDAYS,T1.ESTIMATEDISCPCT,T1.MODIFIEDDATETIME,T1.DEL_MODIFIEDTIME,T1.MODIFIEDBY,T1.CREATEDDATETIME,T1.DEL_CREATEDTIME,T1.RECVERSION,T1.PARTITION,T1.RECID,T2.ACCOUNTNUM,T2.CONTACTPERSONID,T2.RECVERSION,T2.PARTITION,
T2.RECID,T3.BUSINESSACTIVITY_SA,T3.DEL_TRADENAME_SA,T3.BUSINESSACTIVITYDESC_SA,T3.FILENUMBER_SA,T3.DEL_ADDRESSBUILDING_SA,T3.DEL_ORGANIZATIONNUM_SA,T3.COMPANYNAFCODE,T3.BUSINESSNUMBER_CA,T3.SOFTWAREIDENTIFICATIONCODE_CA,T3.FISCALCODE_IT,T3.COMPANYTYPE_MX,T3.RFC_MX,T3.CURP_MX,
T3.STATEINSCRIPTION_MX,T3.LEGALNATURE_IT,T3.DEL_NAME,T3.DEL_ADDRESS,T3.DEL_PHONE,T3.DEL_TELEFAX,T3.BANK,T3.GIRO,T3.REGNUM,T3.COREGNUM,T3.VATNUM,T3.DEL_CURRENCYCODE,T3.IMPORTVATNUM,T3.DEL_ZIPCODE,T3.DEL_STATE,T3.DEL_COUNTY,T3.DEL_COUNTRYREGIONID,T3.DEL_TELEX,T3.DEL_URL,
T3.DEL_EMAIL,T3.DEL_CELLULARPHONE,T3.DEL_PHONELOCAL,T3.UPSNUM,T3.TAX1099REGNUM,T3.NAMECONTROL,T3.TCC,T3.DEL_EUROCURRENCYCODE,T3.KEY_,T3.DEL_SECONDARYCURRENCYCODE,T3.DVRID,T3.DEL_LANGUAGEID,T3.INTRASTATCODE,T3.GIROCONTRACT,T3.GIROCONTRACTACCOUNT,T3.BRANCHID,T3.VATNUMBRANCHID,
T3.IMPORTVATNUMBRANCHID,T3.ACTIVITYCODE,T3.DEL_STREET,T3.DEL_CITY,T3.CONVERSIONDATE,T3.DEL_PAGER,T3.DEL_SMS,T3.ADDRFORMAT,T3.COMPANYREGCOMFR,T3.PACKMATERIALFEELICENSENUM,T3.DEL_COMPANYIDNAF,T3.PAYMROUTINGDNB,T3.PAYMTRADERNUMBER,T3.DEL_PAYMINSTRUCTIONID1,T3.DEL_PAYMINSTRUCTIONID2,
T3.DEL_PAYMINSTRUCTIONID3,T3.DEL_PAYMINSTRUCTIONID4,T3.ISSUINGSIGNATURE,T3.SIACODE,T3.BANKCENTRALBANKPURPOSECODE,T3.BANKCENTRALBANKPURPOSETEXT,T3.DBA,T3.FOREIGNENTITYINDICATOR,T3.COMBINEDFEDSTATEFILER,T3.LASTFILINGINDICATOR,T3.VALIDATE1099ONENTRY,T3.LEGALFORMFR,
T3.SHIPPINGCALENDARID,T3.ENTERPRISENUMBER,T3.BRANCHNUMBER,T3.CUSTOMSCUSTOMERNUMBER_FI,T3.CUSTOMSLICENSENUMBER_FI,T3.DATAAREA,T3.PLANNINGCOMPANY,T3.TAXREPRESENTATIVE,T3.DEL_FALLBACKINVENTLOCATIONID,T3.DEL_ENABLENORWAY,T3.ORGID,T3.DEL_FISCALCALENDAR,T3.BANKACCTUSEDFOR1099,
T3.PAYMINSTRUCTION1,T3.PAYMINSTRUCTION2,T3.PAYMINSTRUCTION3,T3.PAYMINSTRUCTION4,T3.DEL_MODIFIEDBY,T3.DEL_MODIFIEDDATETIME,T3.DEL_MODIFIEDDATETIMETZID,T3.DEL_MODIFIEDDATE,T3.DEL_MODIFIEDDATETZID,T3.LEGALREPRESENTATIVENAME_MX,T3.LEGALREPRESENTATIVERFC_MX,T3.LEGALREPRESENTATIVECURP_MX,
T3.FICREDITORID_DK,T3.ISCONSOLIDATIONCOMPANY,T3.ISELIMINATIONCOMPANY,T3.DEL_MODTIME,T3.DEL_FALLBACKINVENTLOCATIONID1_41,T3.DEL_MODTIME_RU,T3.DEL_GBTORGNUM_CN,T3.DEL_GBTINDUSTRY_CN,T3.DEL_GBTORGTYPE_CN,T3.ACCOUNTINGPERSONNEL_JP,T3.TEMPLATEFOLDER_W,T3.COMPANYREPRESENTATIVE_JP,
T3.CNAE_BR,T3.DEL_USESEVERALADDRESSFORMATTYPES_RU,T3.DEL_PERMANENTACCOUNTNUMBER_IN,T3.DEL_ASSESSINGOFFICERNUMBER_IN,T3.DEL_CIRCLENUMBER_IN,T3.DEL_WARDNUMBER_IN,T3.DEL_TYPEOFDEDUCTOR_IN,T3.DEL_TRIBUTARYSUBSTITUTIONREGISTRY_BR,T3.DEL_USEHOLIDAYCALENDAR_JP,T3.DEL_PERMANENTACCOUNTSTATUS_IN,
T3.DEL_PAOREGNUM_IN,T3.DEL_DDOREGNUM_IN,T3.DEL_DDOCODE_IN,T3.DEL_PAOCODE_IN,T3.DEL_MINISTRYTYPE_IN,T3.DEL_MINISTRYNAME_IN,T3.DEL_MINISTRYCODE_IN,T3.DEL_STATECODE_IN,T3.RESIDENT_W,T3.DEL_IMNSCODE_RU,T3.DEL_IMNSNAME_RU,T3.RALIENCORPCOUNTRY,T3.RALIENCORPNAME,T3.RFULLNAME,
T3.ENTERPRISECODE,T3.COMMERCIALREGISTERSECTION,T3.COMMERCIALREGISTERINSETNUMBER,T3.COMMERCIALREGISTER,T3.DEL_ACCOUNTINGBOOKTYPE_BR,T3.DEL_ACCOUNTINGORIGIN_BR,T3.ACCOUNTANT_LT,T3.ACCOUNTOFFICEREFNUM,T3.BUSINESSCOMMENCEDDATE_JP,T3.BUSINESSINITIALCAPITAL_JP,T3.BUSINESSITEM_JP,
T3.CERTIFIEDTAXACCOUNTANT_JP,T3.CUC_IT,T3.HEAD_LT,T3.LEGALREPRESENTATIVE_JP,T3.PERSONINCHARGE_JP,T3.PRINTCORRINVOICELABEL_DE,T3.PRINTCORRINVOICELABELEFFDATE_DE,T3.PRINTENTERPRISEREGISTER_NO,T3.PRINTINNKPPINADDRESS_RU,T3.TAXAUTHORITY_RU,T3.XX_REGMERCANTIL,T3.DEL_CCMNUM_BR,
T3.DEL_CNPJCPFNUM_BR,T3.DEL_IENUM_BR,T3.DEL_SHADOW_DATAAREAID,T3.DEL_RELATIONTYPENAME_OMINTERNALORG,T3.ORGANIZATIONTYPE,T3.DEL_OMOPERATINGUNIT_SHADOW_DATAAREAID,T3.OMOPERATINGUNITTYPE,T3.HCMWORKER,T3.OMOPERATINGUNITNUMBER,T3.INITIALS,T3.CHILDRENNAMES,T3.DEL_BIRTHDATE,
T3.MARITALSTATUS,T3.DEL_ANNIVERSARYDATE,T3.HOBBIES,T3.GENDER,T3.DEL_SIPELECTRONICADDRESSTYPE,T3.NAMESEQUENCE,T3.PHONETICFIRSTNAME,T3.PHONETICMIDDLENAME,T3.PHONETICLASTNAME,T3.PERSONALTITLE,T3.PERSONALSUFFIX,T3.PROFESSIONALTITLE,T3.PROFESSIONALSUFFIX,T3.BIRTHMONTH,
T3.BIRTHDAY,T3.BIRTHYEAR,T3.ANNIVERSARYMONTH,T3.ANNIVERSARYDAY,T3.ANNIVERSARYYEAR,T3.DEL_DIRPERSON_SHADOW_DATAAREAID,T3.COMMUNICATORSIGNIN,T3.NUMBEROFEMPLOYEES,T3.ORGNUMBER,T3.ABC,T3.DEL_DIRORGANIZATION_SHADOW_DATAAREAID,T3.TEAMMEMBERSHIPCRITERION,T3.DESCRIPTION,T3.ISACTIVE,
T3.TEAMADMINISTRATOR,T3.DEL_OMTEAM_SHADOW_DATAAREAID,T3.PHONETICNAME,T3.DEL_DIRORGBASE_SHADOW_DATAAREAID,T3.DUNSNUMBERRECID,T3.DEL_RELATIONTYPENAME_DIRORGANIZATIONBASE,T3.DEL_GENERATIONALSUFFIX,T3.NAME,T3.DEL_SALUTATION,T3.DEL_PERSONNAMEORDER,T3.LANGUAGEID,T3.DEL_TYPE,
T3.DEL_PREFIX,T3.DEL_PROFESSIONALSUFFIX,T3.DEL_DATAAREAID,T3.DEL_FIRSTNAME,T3.DEL_MIDDLENAME,T3.DEL_LASTNAME,T3.DEL_PARTYID,T3.NAMEALIAS,T3.PARTYNUMBER,T3.DEL_ENTITYTYPE,T3.DEL_NAMESEQUENCE,T3.DEL_PHONETICNAME,T3.INSTANCERELATIONTYPE,T3.KNOWNAS,T3.DEL_INSTANCERELATIONTYPENAME,
T3.DEL_RELATIONTYPENAME,T3.PRIMARYADDRESSLOCATION,T3.PRIMARYCONTACTEMAIL,T3.PRIMARYCONTACTFAX,T3.PRIMARYCONTACTPHONE,T3.PRIMARYCONTACTTELEX,T3.PRIMARYCONTACTURL,T3.MODIFIEDDATETIME,T3.MODIFIEDBY,T3.CREATEDDATETIME,T3.CREATEDBY,T3.RECVERSION,T3.RELATIONTYPE,T3.PARTITION,
T3.RECID,T4.RECVERSION,T4.PARTITION,T4.RECID,T5.ACCOUNTNUM,T5.DEL_OTHERTENDERINFINALIZING,T5.POSTASSHIPMENT,T5.USEORDERNUMBERREFERENCE,T5.RECEIPTOPTION,T5.RECEIPTEMAIL,T5.NONCHARGABLEACCOUNT,T5.REQUIRESAPPROVAL,T5.IMAGE,T5.MODIFIEDDATETIME,T5.DEL_MODIFIEDTIME,
T5.MODIFIEDBY,T5.RECVERSION,T5.PARTITION,T5.RECID,T6.ACCOUNTNUM,T6.GENERATEASN,T6.FULFILLMENTTYPE,T6.FULFILLMENTRATE,T6.FILLENTIREORDER,T6.MODIFIEDDATETIME,T6.MODIFIEDBY,T6.RECVERSION,T6.PARTITION,T6.RECID,T7.NAME,T7.RECVERSION,T7.RECID,T7.INSTANCERELATIONTYPE,T8.PERSON,
T8.FIRSTNAME,T8.MIDDLENAME,T8.LASTNAME,T8.VALIDFROM,T8.VALIDFROMTZID,T8.VALIDTO,T8.VALIDTOTZID,T8.DEL_SHADOW_DATAAREAID,T8.MODIFIEDBY,T8.CREATEDBY,T8.RECVERSION,T8.PARTITION,T8.RECID,T1.MEMO,T3.DEL_MEMO 
FROM  CUSTTABLE T1 LEFT OUTER JOIN CUSTCOLLECTIONSCONTACT T2 ON (((T2.PARTITION=?) AND (T2.DATAAREAID=?)) AND (T1.ACCOUNTNUM=T2.ACCOUNTNUM)) CROSS JOIN DIRPARTYTABLE T3 LEFT OUTER JOIN TAXINFORMATIONCUSTTABLE_IN T4 ON (((T4.PARTITION=?) AND (T4.DATAAREAID=?)) 
AND (T1.ACCOUNTNUM=T4.CUSTTABLE)) LEFT OUTER JOIN RETAILCUSTTABLE T5 ON (((T5.PARTITION=?) AND (T5.DATAAREAID=?)) AND (T1.ACCOUNTNUM=T5.ACCOUNTNUM)) LEFT OUTER JOIN WHSCUSTTABLE T6 ON (((T6.PARTITION=?) AND (T6.DATAAREAID=?)) AND (T1.ACCOUNTNUM=T6.ACCOUNTNUM)) 
LEFT OUTER JOIN DIRPARTYTABLE T7 ON ((T7.PARTITION=?) AND (T1.PARTY=T7.RECID)) LEFT OUTER JOIN DIRPERSONNAME T8 ON ((T8.PARTITION=?) AND (((T8.VALIDFROM<=?) AND (T8.VALIDTO>=?)) AND (T3.RECID=T8.PERSON))) WHERE ((T1.PARTITION=?) AND (T1.DATAAREAID=?)) 
AND ((T3.PARTITION=?) AND (T1.PARTY=T3.RECID)) ORDER BY T1.ACCOUNTNUM OPTION(FAST 1)

A primera vista, observamos que no se trata de una consulta “ligera”, se trata de una consulta en la que participan unas cuantas tablas:

img0005

Luego, podemos comprobar como en la sentencia aparece el campo XX_REGMERCANTIL que, de forma maligna ;), hemos puesto en la tabla CompanyInfo (aparece hacia el final de la línea 23 de la consulta SQL).

 

Bien, ahora vamos a forzar un poco más la máquina, he añadido un segundo campo (también string de 1000 caracteres) en la CompanyInfo.

Para darle un poco más de sustancia, he rellenado el campo con un texto automático sacado de la genial página http://chiquitoipsum.com

Ahora, cuando intento abrir el formulario de clientes (CustTable) desde el ListPage general de clientes (simplemente realizando doble clic sobre alguno de los registros de cliente que aparecen) sucede lo siguiente:

img0006

 

Si ya de por si supone un problema sobrecargar las consultas habituales con gran cantidad de datos, en nuestro ejemplo hemos topado con otro impedimento.

En los parámetros de la instancia del AOS, existe un parámetro de rendimiento, donde se especifica un tamaño máximo de memoria que se usará como buffer de datos en las consultas SQL.

Este parámetro es importante mantenerlo en un valor bajo para no penalizar el rendimiento del sistema en cuanto a acceso a la base de datos.

 

Solución

Lo que suele pasar cuando el sistema saca este mensaje es que el departamento técnico de turno (bajo órdenes de consultoría, dirección de proyecto, usuario clave o ente similar) procede a aumentar dicho parámetro en la configuración del AOS y …. Listos!

Por el bien del sistema, cuando sea posible, lo mejor es intentar analizar el origen del problema y darle una solución que no penalice el rendimiento ni, por supuesto, suponga un gran cambio en el modelo desarrollado.

En nuestro caso, bastaría con sacar ese par de campos de la tabla CompanyInfo y ponerlos en una tabla nueva destinada a almacenar esta información.

 

Saludos,

(Happy DAXing ! 😉 )

Publicaciones Recientes

Dejar comentario