Please, be advised, the method CIBlockElement::GetList of Information blocks module can handle product's data (if Commercial Catalog is available). This is detailed in the documentation and actively used in both public and administrative pages and scripts. However, due to system architectural specifics, this causes significant decrease of performance.
Let's make different calls of CIBlockElement::GetList and see, which queries will be executed at the end.
First, retrieve an empty selection of products from iblock with ID = 2:
SELECT BE.ID as ID,BE.NAME as NAME,BE.IBLOCK_ID as IBLOCK_ID
FROM b_iblock B
INNER JOIN b_lang L ON B.LID=L.LID
INNER JOIN b_iblock_element BE ON BE.IBLOCK_ID = B.ID
WHERE 1=1
AND (
((((BE.IBLOCK_ID = '2'))))
)
AND (((BE.WF_STATUS_ID=1 AND BE.WF_PARENT_ELEMENT_ID IS NULL)))
Now, add filtering by the product availability to the fetch:
SELECT BE.ID as ID,BE.NAME as NAME,BE.IBLOCK_ID as IBLOCK_ID ,CAT_PR.QUANTITY as CATALOG_QUANTITY,
IF (CAT_PR.QUANTITY_TRACE = 'D', 'Y', CAT_PR.QUANTITY_TRACE) as CATALOG_QUANTITY_TRACE,
CAT_PR.QUANTITY_TRACE as CATALOG_QUANTITY_TRACE_ORIG, CAT_PR.WEIGHT as CATALOG_WEIGHT,
CAT_PR.VAT_ID as CATALOG_VAT_ID, CAT_PR.VAT_INCLUDED as CATALOG_VAT_INCLUDED,
IF (CAT_PR.CAN_BUY_ZERO = 'D', 'N', CAT_PR.CAN_BUY_ZERO) as CATALOG_CAN_BUY_ZERO,
CAT_PR.CAN_BUY_ZERO as CATALOG_CAN_BUY_ZERO_ORIG,
CAT_PR.PURCHASING_PRICE as CATALOG_PURCHASING_PRICE, CAT_PR.PURCHASING_CURRENCY as CATALOG_PURCHASING_CURRENCY,
CAT_PR.QUANTITY_RESERVED as CATALOG_QUANTITY_RESERVED,
IF (CAT_PR.SUBSCRIBE = 'D', 'Y', CAT_PR.SUBSCRIBE) as CATALOG_SUBSCRIBE, CAT_PR.SUBSCRIBE as CATALOG_SUBSCRIBE_ORIG,
CAT_PR.WIDTH as CATALOG_WIDTH, CAT_PR.LENGTH as CATALOG_LENGTH, CAT_PR.HEIGHT as CATALOG_HEIGHT,
CAT_PR.MEASURE as CATALOG_MEASURE, CAT_PR.TYPE as CATALOG_TYPE, CAT_PR.AVAILABLE as CATALOG_AVAILABLE,
CAT_PR.BUNDLE as CATALOG_BUNDLE, CAT_PR.PRICE_TYPE as CATALOG_PRICE_TYPE,
CAT_PR.RECUR_SCHEME_LENGTH as CATALOG_RECUR_SCHEME_LENGTH, CAT_PR.RECUR_SCHEME_TYPE as CATALOG_RECUR_SCHEME_TYPE,
CAT_PR.TRIAL_PRICE_ID as CATALOG_TRIAL_PRICE_ID, CAT_PR.WITHOUT_ORDER as CATALOG_WITHOUT_ORDER,
CAT_PR.SELECT_BEST_PRICE as CATALOG_SELECT_BEST_PRICE,
IF (CAT_PR.NEGATIVE_AMOUNT_TRACE = 'D', 'N', CAT_PR.NEGATIVE_AMOUNT_TRACE) as CATALOG_NEGATIVE_AMOUNT_TRACE,
CAT_PR.NEGATIVE_AMOUNT_TRACE as CATALOG_NEGATIVE_AMOUNT_TRACE_ORIG, CAT_VAT.RATE as CATALOG_VAT
FROM b_iblock B
INNER JOIN b_lang L ON B.LID=L.LID
INNER JOIN b_iblock_element BE ON BE.IBLOCK_ID = B.ID
left join b_catalog_product as CAT_PR on (CAT_PR.ID = BE.ID)
left join b_catalog_iblock as CAT_IB on ((CAT_PR.VAT_ID IS NULL or CAT_PR.VAT_ID = 0) and CAT_IB.IBLOCK_ID = BE.IBLOCK_ID)
left join b_catalog_vat as CAT_VAT on
(CAT_VAT.ID = IF((CAT_PR.VAT_ID IS NULL OR CAT_PR.VAT_ID = 0), CAT_IB.VAT_ID, CAT_PR.VAT_ID))
WHERE 1=1
AND (
((((BE.IBLOCK_ID = '2'))))
AND ((((CAT_PR.AVAILABLE='Y'))))
)
AND (((BE.WF_STATUS_ID=1 AND BE.WF_PARENT_ELEMENT_ID IS NULL)))
This way, any query to product data (filtering, sorting, fetching a field) leads to join of three tables and selection of all product fields.
Remove filtration and select a one price type (price type ID - 1):
SELECT BE.ID as ID,BE.NAME as NAME,BE.IBLOCK_ID as IBLOCK_ID,
CAT_P1.CATALOG_GROUP_ID as CATALOG_GROUP_ID_1, CAT_P1.ID as CATALOG_PRICE_ID_1,
CAT_P1.PRICE as CATALOG_PRICE_1, CAT_P1.CURRENCY as CATALOG_CURRENCY_1,
CAT_P1.QUANTITY_FROM as CATALOG_QUANTITY_FROM_1, CAT_P1.QUANTITY_TO as CATALOG_QUANTITY_TO_1,
CAT_P1.EXTRA_ID as CATALOG_EXTRA_ID_1,
'Базовая цена' as CATALOG_GROUP_NAME_1, 'Y' as CATALOG_CAN_ACCESS_1, 'Y' as CATALOG_CAN_BUY_1,
CAT_PR.QUANTITY as CATALOG_QUANTITY, IF (CAT_PR.QUANTITY_TRACE = 'D', 'Y', CAT_PR.QUANTITY_TRACE) as CATALOG_QUANTITY_TRACE,
CAT_PR.QUANTITY_TRACE as CATALOG_QUANTITY_TRACE_ORIG, CAT_PR.WEIGHT as CATALOG_WEIGHT,
CAT_PR.VAT_ID as CATALOG_VAT_ID, CAT_PR.VAT_INCLUDED as CATALOG_VAT_INCLUDED,
IF (CAT_PR.CAN_BUY_ZERO = 'D', 'N', CAT_PR.CAN_BUY_ZERO) as CATALOG_CAN_BUY_ZERO,
CAT_PR.CAN_BUY_ZERO as CATALOG_CAN_BUY_ZERO_ORIG, CAT_PR.PURCHASING_PRICE as CATALOG_PURCHASING_PRICE,
CAT_PR.PURCHASING_CURRENCY as CATALOG_PURCHASING_CURRENCY, CAT_PR.QUANTITY_RESERVED as CATALOG_QUANTITY_RESERVED,
IF (CAT_PR.SUBSCRIBE = 'D', 'Y', CAT_PR.SUBSCRIBE) as CATALOG_SUBSCRIBE, CAT_PR.SUBSCRIBE as CATALOG_SUBSCRIBE_ORIG,
CAT_PR.WIDTH as CATALOG_WIDTH, CAT_PR.LENGTH as CATALOG_LENGTH, CAT_PR.HEIGHT as CATALOG_HEIGHT,
CAT_PR.MEASURE as CATALOG_MEASURE, CAT_PR.TYPE as CATALOG_TYPE, CAT_PR.AVAILABLE as CATALOG_AVAILABLE,
CAT_PR.BUNDLE as CATALOG_BUNDLE, CAT_PR.PRICE_TYPE as CATALOG_PRICE_TYPE,
CAT_PR.RECUR_SCHEME_LENGTH as CATALOG_RECUR_SCHEME_LENGTH, CAT_PR.RECUR_SCHEME_TYPE as CATALOG_RECUR_SCHEME_TYPE,
CAT_PR.TRIAL_PRICE_ID as CATALOG_TRIAL_PRICE_ID, CAT_PR.WITHOUT_ORDER as CATALOG_WITHOUT_ORDER,
CAT_PR.SELECT_BEST_PRICE as CATALOG_SELECT_BEST_PRICE,
IF (CAT_PR.NEGATIVE_AMOUNT_TRACE = 'D', 'N', CAT_PR.NEGATIVE_AMOUNT_TRACE) as CATALOG_NEGATIVE_AMOUNT_TRACE,
CAT_PR.NEGATIVE_AMOUNT_TRACE as CATALOG_NEGATIVE_AMOUNT_TRACE_ORIG, CAT_VAT.RATE as CATALOG_VAT
FR OM b_iblock B
INNER JOIN b_lang L ON B.LID=L.LID
INNER JOIN b_iblock_element BE ON BE.IBLOCK_ID = B.ID
left join b_catalog_price as CAT_P1 on (CAT_P1.PRODUCT_ID = BE.ID and CAT_P1.CATALOG_GROUP_ID = 1)
left join b_catalog_product as CAT_PR on (CAT_PR.ID = BE.ID)
left join b_catalog_iblock as CAT_IB on ((CAT_PR.VAT_ID IS NULL or CAT_PR.VAT_ID = 0) and CAT_IB.IBLOCK_ID = BE.IBLOCK_ID)
left join b_catalog_vat as CAT_VAT on (CAT_VAT.ID = IF((CAT_PR.VAT_ID IS NULL OR CAT_PR.VAT_ID = 0), CAT_IB.VAT_ID, CAT_PR.VAT_ID))
WH ERE 1=1
AND (
((((BE.IBLOCK_ID = '2'))))
)
AND (((BE.WF_STATUS_ID=1 AND BE.WF_PARENT_ELEMENT_ID IS NULL)))
If we attempt to additionally retrieve warehouse data as well, the situation will be similar.
Let's highlight interim results:
You must strictly avoid retrieving prices and available warehouse stock in CIBlockElement::GetList (specifically, if sorting is used, no matter by which fields). This data must be retrieved using separate API calls. By the way, this can be done in standard components starting from version 17.0.
Filtering and sorting by product fields, prices, warehouses remains. Querying product fields by keys CATALOG_ gives an extra join of three tables. Querying N types of prices or warehouses - join N+3 tables. In addition to increased query time, you can get an error MySql "Too many tables; MySQL can only use 61 tables in a join".
Before the release of catalog 18.6.100 + iblock 18.6.200, all of the abovementioned is related to standard components and Iblock module admin lists (specifically, in the joint view mode for sections and elements, view the details below). New product handling features become available after the these updates are released in CIBlockElement::GetList.
Note: previously, we recommended to avoid using joint view mode for all large iblocks due to significant memory consumption. WIth the release of Information blocks module version 18.5.5, this issue has been resolved: this mode allows to display an iblock with 100 thousands elements in the administrative section (memory consumption is reduced approx. 2o times).
Startng from Catalog version 18.6.100 + iblock 18.6.200
Starting from iblock version 18.6.200, method keys are updated. You can filter, sort, get by all keys.
Product fields
Key
Description
TYPE
Product type. Values:
1 - Standard product
2 - Bundle
3 - Product with quote
4 - Quote
AVAILABLE
Availability.
BUNDLE
Bundle availability.
QUANTITY
Available quantiy.
QUANTITY_RESERVED
Reserved quantity.
QUANTITY_TRACE
Stock control is enabled (with account of module settings default values) - Y/N.
QUANTITY_TRACE_RAW
Stock control is enabled (raw value) - Y/N/D.
CAN_BUY_ZERO
Allow to purchase out-of-stock items (with account of module settings default values) - Y/N.
CAN_BUY_ZERO_RAW
Allow to purchase out-of-stock items (raw value) - Y/N/D.
SUBSCRIBE
Allow subscription to back in stock notifications (with account of module settings default values) - Y/N.
SUBSCRIBE_RAW
Allow subscription to back in stock notifications (raw value) - Y/N/D.
VAT_ID
Product VAT ID.
VAT_INCLUDED
Tax included attribute.
PURCHASING_PRICE
Purchase price.
PURCHASING_CURRENCY
Purchase price currency.
BARCODE_MULTI
Multiple barcodes.
WEIGHT
Weight.
WIDTH
Width.
LENGTH
Length.
HEIGHT
Height.
MEASURE
Unit of measurement ID.
PAYMENT_TYPE
Subscription payment type.
RECUR_SCHEME_LENGTH
Recurring payment time period.
RECUR_SCHEME_TYPE
Recurring payment time unit.
TRIAL_PRICE_ID
Trial payment for product.
WITHOUT_ORDER
Prolongation without ordering.
Catalog 20.0.200 module version introduces product fields
Key
Description
PRODUCT_BARCODE
Barcode.
PRODUCT_BARCODE_STORE
Warehouse barcode.
PRODUCT_BARCODE_ORDER
Order barcode.
Now calling method with filtration by availability looks as follows:
and the query contains only requested data and only a single join:
SELECT BE.ID as ID,BE.NAME as NAME,BE.IBLOCK_ID as IBLOCK_ID
FROM b_iblock B
INNER JOIN b_lang L ON B.LID=L.LID
INNER JOIN b_iblock_element BE ON BE.IBLOCK_ID = B.ID
left join b_catalog_product as PRD on (PRD.ID = BE.ID)
WHERE 1=1
AND (
((((BE.IBLOCK_ID = '2'))))
AND ((((PRD.AVAILABLE='Y'))))
)
AND (((BE.WF_STATUS_ID=1 AND BE.WF_PARENT_ELEMENT_ID IS NULL)))
Retrieve selection of sizes and weight of available standard products:
SELECT BE.ID as ID,BE.NAME as NAME,BE.IBLOCK_ID as IBLOCK_ID ,
PRD.WEIGHT as WEIGHT, PRD.WIDTH as WIDTH, PRD.HEIGHT as HEIGHT, PRD.LENGTH as LENGTH
FROM b_iblock B
INNER JOIN b_lang L ON B.LID=L.LID
INNER JOIN b_iblock_element BE ON BE.IBLOCK_ID = B.ID
left join b_catalog_product as PRD on (PRD.ID = BE.ID)
WHERE 1=1
AND (
((((BE.IBLOCK_ID = '2'))))
AND ((((PRD.AVAILABLE='Y'))))
AND ((((PRD.TYPE = '1'))))
)
AND (((BE.WF_STATUS_ID=1 AND BE.WF_PARENT_ELEMENT_ID IS NULL)))
Price fields (without binding to a specific price type)
Key
Description
Available for the following
PRICE_TYPE
Price type ID.
Filter.
PRICE
Price.
Filter.
CURRENCY
Currency.
Filter.
QUANTITY_TO
Minimum product quantity.
Filter.
QUANTITY_FROM
Maximum product quantity.
Filter.
EXTRA_ID
Extra charge ID.
Filter.
SCALED_PRICE
Price in base currency.
Filter.
QUANTITY_RANGE_FILTER
Search prices for specified product quantity.
Filter only, auxiliary.
CURRENCY_FOR_SCALE
Filtration by price with indicated currency (i. e. when required to filter prices in any currencies with account of exchange rate.
Filter only, auxiliary.
Price fields (With indicated price type)
Key
Description
Available for the following:
PRICE_ID
Price.
Filter, sorting, selection.
CURRENCY_ID
Currency.
Filter, sorting, selection.
QUANTITY_TO_ID
Minimum product quantity.
Filter, sorting, selection.
QUANTITY_FROM_ID
Maximum product quantity.
Filter, sorting, selection.
EXTRA_ID_ID
Extra price ID.
Filter, sorting, selection.
SCALED_PRICE_ID
Price in base currency.
Filter, sorting, selection.
QUANTITY_RANGE_FILTER_ID
Search prices for quantity of products.
Only filter, auxiliary.
CURRENCY_FOR_SCALE_ID
Filtering by price with indicated currency (i. e. when you require filtering price in any currencies with account of exchange rate).
Upon installing updates catalog 18.6.100 + iblock 18.6.200, it's strongly recommended to transition your components and scripts to new keys. Performance increase is directly proportional to the number of products in catalog. Accordingly, test section with 1,5 thousand of products resulted in execution speed increase was 30%. Standard components (
catalog.section
Компонент выводит список элементов раздела с указанным набором свойств.